using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;

namespace MindPowerSdk
{
    public enum ModelObjType : uint
    {
        Geometry = 1,
        Helper = 2
    }

    public class lwModelObjInfo
    {
        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        struct lwModelObjInfoHeader
        {
            public ModelObjType Type;
            public uint Addr;
            public uint Size;
        }

        public int GeomObjNum;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public lwGeomObjInfo[] GeomObjSeq; // 最多32个

        public int Load(string file)
        {
            string filePath = Path.Combine(GlobalDefine.ClientDir, file);
            using FileStream fs = File.OpenRead(filePath);
            using BinaryReader fp = new BinaryReader(fs);

            uint version = fp.ReadUInt32();
            int objNum = fp.ReadInt32();

            lwModelObjInfoHeader[] header = new lwModelObjInfoHeader[objNum];
            for (int i = 0; i < objNum; i++)
            {
                var h = StructReader.ReadStruct<lwModelObjInfoHeader>(fp);
                header[i] = h;
            }

            GeomObjNum = 0;
            GeomObjSeq = new lwGeomObjInfo[32];
            for (int i = 0; i < objNum; i++)
            {
                var headerInfo = header[i];
                fs.Seek(headerInfo.Addr, SeekOrigin.Begin);

                switch (headerInfo.Type)
                {
                    case ModelObjType.Geometry:
                    {
                        this.GeomObjSeq[GeomObjNum] = new lwGeomObjInfo();
                        if (version == 0) // EXP_OBJ_VERSION_0_0_0_0
                        {
                            int old_version = fp.ReadInt32();
                        }

                        this.GeomObjSeq[GeomObjNum].Load(fp, version);
                        GeomObjNum += 1;
                        break;
                    }
                    case ModelObjType.Helper:
                    {
                        break;
                    }
                }
            }

            return 0;
        }
    }

    public enum lwModelObjectLoadType
    {
        MODELOBJECT_LOAD_RESET = 0,
        MODELOBJECT_LOAD_MERGE = 1,
        MODELOBJECT_LOAD_MERGE2 = 2
    };

    public struct lwRenderCtrlCreateInfo
    {
        public uint ctrl_id;
        public uint decl_id;
        public uint vs_id;
        public uint ps_id;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class lwStateCtrl
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        /* this+0x0 */
        public byte[] _state_seq; // MindPower::lwObjectStateEnum ??? 

        public void SetState(uint state, byte value)
        {
            this._state_seq[state] = value;
        }
    }

    public class lwGeomObjInfo
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        /* this+0x4 */
        public struct lwGeomObjInfoHeader
        {
            /* this+0x0 */
            public uint id;

            /* this+0x4 */
            public uint parent_id;

            /* this+0x8 */
            public lwModelObjectLoadType type;

            /* this+0xc */
            public Matrix4x4 mat_local;

            /* this+0x4c */
            public lwRenderCtrlCreateInfo rcci;

            /* this+0x5c */
            public lwStateCtrl state_ctrl;

            /* this+0x64 */
            public uint mtl_size;

            /* this+0x68 */
            public uint mesh_size;

            /* this+0x6c */
            public uint helper_size;

            /* this+0x70 */
            public uint anim_size;
        };

        /* this+0x4 */
        public lwGeomObjInfoHeader header;

        /* this+0x78 */
        public uint mtl_num;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x7c */
        public lwMtlTexInfo[] mtl_seq;

        /* this+0x80 */
        public lwMeshInfo mesh;

        /* this+0x130 */
        public lwHelperInfo helper_data;

        /* this+0x160 */
        public lwAnimDataInfo anim_data;

        public int Load(BinaryReader fp, uint version)
        {
            this.header = StructReader.ReadStruct<lwGeomObjInfoHeader>(fp);
            this.header.state_ctrl.SetState(5, 0);
            this.header.state_ctrl.SetState(3, 1);
            if (this.header.mtl_size > 100000)
            {
                // System.Windows.Forms.MessageBox.Show("iii", "error");
                return -1;
            }

            if (this.header.mtl_size > 0)
            {
                // lwLoadMtlTexInfo(ref this.mtl_seq, ref this.mtl_num, fp, version);
            }

            if (this.header.mesh_size > 0)
            {
                // lwMeshInfo_Load(ref this.mesh, fp, version);
            }

            if (this.header.helper_size > 0)
            {
                // this.helper_data.Load(fp, version);
            }

            if (this.header.anim_size > 0)
            {
                this.anim_data = new lwAnimDataInfo();
                // this.anim_data.Load(fp, version);
            }

            return 0;
        }

        public int Load(string file)
        {
            if (!File.Exists(file))
                return -1;
            FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read);
            BinaryReader fp = new BinaryReader(fs);

            uint version = fp.ReadUInt32();
            int ret = this.Load(fp, version);
            fp.Close();
            fs.Close();
            return ret;
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class lwMtlTexInfo
    {
        /* this+0x0 */
        public float opacity;

        /* this+0x4 */
        [MarshalAs(UnmanagedType.U4)] public lwMtlTexInfoTransparencyTypeEnum transp_type; // MindPower::lwMtlTexInfoTransparencyTypeEnum 

        /* this+0x8 */
        public lwMaterial mtl;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        /* this+0x4c */
        public lwRenderStateAtom[] rs_set;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        /* this+0xac */
        public lwTexInfo[] tex_seq;
    }

    public enum lwMtlTexInfoTransparencyTypeEnum
    {
        MTLTEX_TRANSP_FILTER = 0,
        MTLTEX_TRANSP_ADDITIVE = 1,
        MTLTEX_TRANSP_ADDITIVE1 = 2,
        MTLTEX_TRANSP_ADDITIVE2 = 3,
        MTLTEX_TRANSP_ADDITIVE3 = 4,
        MTLTEX_TRANSP_SUBTRACTIVE = 5,
        MTLTEX_TRANSP_SUBTRACTIVE1 = 6,
        MTLTEX_TRANSP_SUBTRACTIVE2 = 7,
        MTLTEX_TRANSP_SUBTRACTIVE3 = 8
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct lwMaterial
    {
        /* this+0x0 */
        public Color dif;

        /* this+0x10 */
        public Color amb;

        /* this+0x20 */
        public Color spe;

        /* this+0x30 */
        public Color emi;

        /* this+0x40 */
        public float power;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct lwRenderStateAtom
    {
        /* this+0x0 */
        public uint state; // MindPower::lwRenderStateAtomType 

        /* this+0x4 */
        public uint value0;

        /* this+0x8 */
        public uint value1;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class lwTexInfo
    {
        /* this+0x0 */
        public uint stage;

        /* this+0x4 */
        public uint level;

        /* this+0x8 */
        public uint usage;

        /* this+0xc */
        [MarshalAs(UnmanagedType.U4)] public _D3DFORMAT format;

        /* this+0x10 */
        [MarshalAs(UnmanagedType.U4)] public _D3DPOOL pool;

        /* this+0x14 */
        public uint byte_alignment_flag;

        /* this+0x18 */
        [MarshalAs(UnmanagedType.U4)] public lwTexInfoTypeEnum type;

        /* this+0x1c */
        public uint width;

        /* this+0x20 */
        public uint height;

        /* this+0x24 */
        [MarshalAs(UnmanagedType.U4)] public lwColorKeyTypeEnum colorkey_type;

        /* this+0x28 */
        public Color32 colorkey;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
        /* this+0x2c */
        public char[] file_name;

        /* this+0x6c */
        public uint data_pointer;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        /* this+0x70 */
        public lwRenderStateAtom[] tss_set;
    };

    public enum _D3DFORMAT
    {
        D3DFMT_UNKNOWN = 0x0,
        D3DFMT_R8G8B8 = 0x14,
        D3DFMT_A8R8G8B8 = 0x15,
        D3DFMT_X8R8G8B8 = 0x16,
        D3DFMT_R5G6B5 = 0x17,
        D3DFMT_X1R5G5B5 = 0x18,
        D3DFMT_A1R5G5B5 = 0x19,
        D3DFMT_A4R4G4B4 = 0x1a,
        D3DFMT_R3G3B2 = 0x1b,
        D3DFMT_A8 = 0x1c,
        D3DFMT_A8R3G3B2 = 0x1d,
        D3DFMT_X4R4G4B4 = 0x1e,
        D3DFMT_A2B10G10R10 = 0x1f,
        D3DFMT_G16R16 = 0x22,
        D3DFMT_A8P8 = 0x28,
        D3DFMT_P8 = 0x29,
        D3DFMT_L8 = 0x32,
        D3DFMT_A8L8 = 0x33,
        D3DFMT_A4L4 = 0x34,
        D3DFMT_V8U8 = 0x3c,
        D3DFMT_L6V5U5 = 0x3d,
        D3DFMT_X8L8V8U8 = 0x3e,
        D3DFMT_Q8W8V8U8 = 0x3f,
        D3DFMT_V16U16 = 0x40,
        D3DFMT_W11V11U10 = 0x41,
        D3DFMT_A2W10V10U10 = 0x43,
        D3DFMT_UYVY = 0x59565955,
        D3DFMT_YUY2 = 0x32595559,
        D3DFMT_DXT1 = 0x31545844,
        D3DFMT_DXT2 = 0x32545844,
        D3DFMT_DXT3 = 0x33545844,
        D3DFMT_DXT4 = 0x34545844,
        D3DFMT_DXT5 = 0x35545844,
        D3DFMT_D16_LOCKABLE = 0x46,
        D3DFMT_D32 = 0x47,
        D3DFMT_D15S1 = 0x49,
        D3DFMT_D24S8 = 0x4b,
        D3DFMT_D16 = 0x50,
        D3DFMT_D24X8 = 0x4d,
        D3DFMT_D24X4S4 = 0x4f,
        D3DFMT_VERTEXDATA = 0x64,
        D3DFMT_INDEX16 = 0x65,
        D3DFMT_INDEX32 = 0x66,
        D3DFMT_FORCE_DWORD = 0x7fffffff,
    }

    public enum _D3DPOOL
    {
        D3DPOOL_DEFAULT = 0x0,
        D3DPOOL_MANAGED = 0x1,
        D3DPOOL_SYSTEMMEM = 0x2,
        D3DPOOL_SCRATCH = 0x3,
        D3DPOOL_FORCE_DWORD = 0x7fffffff,
    }

    public enum lwTexInfoTypeEnum
    {
        TEX_TYPE_FILE = 0,
        TEX_TYPE_SIZE = 1,
        TEX_TYPE_DATA = 2,
        TEX_TYPE_INVALID = -1
    }

    public enum lwColorKeyTypeEnum
    {
        COLORKEY_TYPE_NONE = 0,
        COLORKEY_TYPE_COLOR = 1,
        COLORKEY_TYPE_PIXEL = 2
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct lwMeshInfo
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct lwMeshInfoHeader
        {
            /* this+0x0 */
            public uint fvf;

            /* this+0x4 */
            [MarshalAs(UnmanagedType.U4)] public _D3DPRIMITIVETYPE pt_type;

            /* this+0x8 */
            public uint vertex_num;

            /* this+0xc */
            public uint index_num;

            /* this+0x10 */
            public uint subset_num;

            /* this+0x14 */
            public uint bone_index_num;

            /* this+0x18 */
            public uint bone_infl_factor;

            /* this+0x1c */
            public uint vertex_element_num;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            /* this+0x20 */
            public lwRenderStateAtom[] rs_set;
        };

        /* this+0x0 */
        public lwMeshInfoHeader header;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x80 */
        public Vector3[] vertex_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x84 */
        public Vector3[] normal_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x88 */
        public Vector2[] texcoord0_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x8c */
        public Vector2[] texcoord1_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x90 */
        public Vector2[] texcoord2_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x94 */
        public Vector2[] texcoord3_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x98 */
        public uint[] vercol_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0x9c */
        public uint[] index_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0xa0 */
        public uint[] bone_index_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0xa4 */
        public lwBlendInfo[] blend_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0xa8 */
        public lwSubsetInfo[] subset_seq;

        [MarshalAs(UnmanagedType.LPArray)]
        /* this+0xac */
        public _D3DVERTEXELEMENT9[] vertex_element_seq;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct _D3DVERTEXELEMENT9
    {
        /* this+0x0 */
        public ushort Stream;

        /* this+0x2 */
        public ushort Offset;

        /* this+0x4 */
        public byte Type;

        /* this+0x5 */
        public byte Method;

        /* this+0x6 */
        public byte Usage;

        /* this+0x7 */
        public byte UsageIndex;
    };

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct lwSubsetInfo
    {
        /* this+0x0 */
        public uint primitive_num;

        /* this+0x4 */
        public uint start_index;

        /* this+0x8 */
        public uint vertex_num;

        /* this+0xc */
        public uint min_index;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct lwBlendInfo
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        /* this+0x0 */
        public byte[] index;

        /* this+0x0 */
        //uint indexd; 
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        /* this+0x4 */
        public float[] weight;
    }

    public enum _D3DPRIMITIVETYPE
    {
        D3DPT_POINTLIST = 0x1,
        D3DPT_LINELIST = 0x2,
        D3DPT_LINESTRIP = 0x3,
        D3DPT_TRIANGLELIST = 0x4,
        D3DPT_TRIANGLESTRIP = 0x5,
        D3DPT_TRIANGLEFAN = 0x6,
        D3DPT_FORCE_DWORD = 0x7fffffff,
    }
}