using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization;
using Rubberduck.InternalApi.Extensions;
using Rubberduck.InternalApi.Model;
using Rubberduck.InternalApi.Model.Declarations.Symbols;
using Rubberduck.VBEditor.Utility;
using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;
using VARDESC = System.Runtime.InteropServices.ComTypes.VARDESC;

namespace Rubberduck.Parsing.Model.ComReflection;

[DataContract]
[KnownType(typeof(ComType))]
public class ComStruct : ComType, IComTypeWithFields
{
    [DataMember(IsRequired = true)]
    private List<ComField> _fields = new();
    public IEnumerable<ComField> Fields => _fields;

    public ComStruct(IComBase parent, ITypeLib typeLib, ITypeInfo info, TYPEATTR attrib, int index)
        : base(parent, typeLib, attrib, index)
    {
        Type = DeclarationType.UserDefinedType;          
        GetFields(info, attrib);
    }

    private void GetFields(ITypeInfo info, TYPEATTR attrib)
    {
        var names = new string[1];
        for (var index = 0; index < attrib.cVars; index++)
        {
            info.GetVarDesc(index, out IntPtr varPtr);
            using (DisposalActionContainer.Create(varPtr, info.ReleaseVarDesc))
            {
                var desc = Marshal.PtrToStructure<VARDESC>(varPtr);
                info.GetNames(desc.memid, names, names.Length, out int length);
                Debug.Assert(length == 1);

                _fields.Add(new ComField(this, info, names[0], desc, index, DeclarationType.UserDefinedTypeMember));
            }
        }
    }

    public override Symbol ToSymbol(WorkspaceFileUri uri)
    {
        var children = Fields.Select(e => new UserDefinedTypeMemberSymbol(e.Name, uri.GetChildSymbolUri(Name), e.ValueType) { IsUserDefined = false });
        return new UserDefinedTypeSymbol(Name, uri, InternalApi.Model.Accessibility.Public, children) 
        {
            IsUserDefined = false,
            Detail = Documentation.DocString,
        };
    }
}
