using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Quik.FreeType
{
    public static class FT
    {
        private const string freetype2 = "freetype";

        private static readonly string[] LibraryNames = new string[] 
        {
            //FIXME: This is wrong on so many levels, but, i need to do this
            // in order to get a change of this running.
            "runtimes/win-x64/native/libfreetype.dll",
            "runtimes/win-x86/native/libfreetype.dll",
            "runtimes/linux-arm/native/libfreetype.so",
            "runtimes/linux-arm64/native/libfreetype.so",
            "runtimes/linux-x64/native/libfreetype.so",
            "runtimes/native/libfreetype.dylib",
            "libfreetype.dll",
            "libfreetype.so",
            "libfreetype.dylib",
        };

        static FT()
        {
            NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), Resolver);
        }

        private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
        {
            if (libraryName != freetype2)
                return IntPtr.Zero;

            foreach (string name in LibraryNames)
            {
                if (NativeLibrary.TryLoad(name, assembly, searchPath, out IntPtr handle))
                {
                    return handle;
                }
            }

            return NativeLibrary.Load(libraryName);
        }

        [DllImport(freetype2, EntryPoint = "FT_Init_FreeType")]
        public static extern FTError InitFreeType(out FTLibrary library);

        [DllImport(freetype2, EntryPoint = "FT_Done_FreeType")]
        public static extern FTError DoneFreeType(FTLibrary library);

        [DllImport(freetype2, EntryPoint = "FT_New_Face")]
        public static extern FTError NewFace(
            FTLibrary library,
            [MarshalAs(UnmanagedType.LPStr)] string path,
            long faceIndex,
            out FTFace face);

        [DllImport(freetype2, EntryPoint = "FT_New_Memory_Face")]
        public static extern FTError NewMemoryFace(
            FTLibrary library,
            IntPtr buffer,
            long size,
            long faceIndex,
            out FTFace face);

        [DllImport(freetype2, EntryPoint = "FT_New_Memory_Face")]
        public static extern FTError NewMemoryFace(
            FTLibrary library,
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] buffer,
            long size,
            long faceIndex,
            out FTFace face);

        [DllImport(freetype2, EntryPoint = "FT_New_Memory_Face")]
        public static extern FTError NewMemoryFace(
            FTLibrary library,
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] Span<byte> buffer,
            long size,
            long faceIndex,
            out FTFace face);

        // public static extern FTError OpenFace(FTLibrary library, in FTOpenArgs args, long faceIndex, out FTFace face);

        // [DllImport(freetype2, EntryPoint = "FT_Attach_File")]
        // public static extern FTError AttachFile(FTFace face, [MarshalAs(UnmanagedType.LPStr)] string filePathName);

        [DllImport(freetype2, EntryPoint = "FT_Set_Char_Size")]
        public static extern FTError SetCharSize(
            FTFace library,
            long charWidth,
            long charHeight,
            uint horizontalResolution,
            uint verticalResolution);


        [DllImport(freetype2, EntryPoint = "FT_Get_Char_Index")]
        public static extern uint GetCharIndex(FTFace face, ulong charCode);

        [DllImport(freetype2, EntryPoint = "FT_Load_Glyph")]
        public static extern FTError LoadGlyph(FTFace face, uint charIndex, FTLoadFlags flags);

        [DllImport(freetype2, EntryPoint = "FT_Render_Glyph")]
        public static extern FTError RenderGlyph(FTGlyphSlot slot, FTRenderMode mode);

        [DllImport(freetype2, EntryPoint = "FT_Done_Face")]
        public static extern FTError DoneFace(FTFace face);

        [DllImport(freetype2, EntryPoint = "FT_Bitmap_Init")]
        public static extern void BitmapInit(ref FTBitmap bitmap);

        [DllImport(freetype2, EntryPoint = "FT_Bitmap_Convert")]
        public static extern void BitmapConvert(FTLibrary library, in FTBitmap source, ref FTBitmap target,
            int alignment);

        [DllImport(freetype2, EntryPoint = "FT_Bitmap_Done")]
        public static extern void BitmapDone(FTLibrary library, ref FTBitmap bitmap);
    }
}