using UnityEngine;
using UnityEngine.Rendering;
using System;
using System.Runtime.InteropServices;

public class KotlinBridge : MonoBehaviour
{
    static KotlinBridge Instance;

    [StructLayout(LayoutKind.Sequential)]
    struct NativeCallbacks
    {
        public IntPtr OnMessage;
        public IntPtr OnServiceInitialized;
        public IntPtr OnFrameAvailable;
        public IntPtr OnBufferReady;
        public IntPtr OnTextureReady;
    }

    delegate void OnMessageDelegate(string message);
    delegate void OnServiceInitializedDelegate(bool success);
    delegate void OnFrameAvailableDelegate();
    delegate void OnBufferReadyDelegate();
    delegate void OnTextureReadyDelegate(IntPtr nativeTexturePtr, int width, int height, bool isVulkan);

    [DllImport("my_native_lib")]
    static extern void SetNativeCallbacks(ref NativeCallbacks callbacks);

    [DllImport("my_native_lib")]
    public static extern void SendTouchDown(float u, float v);

    [DllImport("my_native_lib")]
    public static extern void SendTouchMove(float u, float v);

    [DllImport("my_native_lib")]
    public static extern void SendTouchUp(float u, float v);

    [DllImport("my_native_lib")]
    static extern IntPtr InitBackend();

    [DllImport("my_native_lib")]
    static extern IntPtr UpdateTexture();

    // Legacy compatibility
    [DllImport("my_native_lib")]
    static extern IntPtr InitGLAD();

    [AOT.MonoPInvokeCallback(typeof(OnMessageDelegate))]
    static void OnMessage(string message)
    {
        // High-speed callback, disabled for performance
        // Debug.Log("Native callback: " + message);
    }

    [AOT.MonoPInvokeCallback(typeof(OnServiceInitializedDelegate))]
    static void OnServiceInitialized(bool success)
    {
        Debug.Log("Service Initialized: " + success);
    }

    [AOT.MonoPInvokeCallback(typeof(OnFrameAvailableDelegate))]
    static void OnFrameAvailable()
    {
        UnityMainThreadDispatcher.Enqueue(() => {
            GL.IssuePluginEvent(UpdateTexture(), 1);
        });
    }

    [AOT.MonoPInvokeCallback(typeof(OnBufferReadyDelegate))]
    static void OnBufferReady()
    {
        Debug.Log("Buffer Ready");
        UnityMainThreadDispatcher.Enqueue(() => {
            GL.IssuePluginEvent(InitBackend(), 1);
        });
    }

    [AOT.MonoPInvokeCallback(typeof(OnTextureReadyDelegate))]
    static void OnTextureReady(IntPtr nativeTexturePtr, int width, int height, bool isVulkan)
    {
        Debug.Log($"Texture Ready: ptr={nativeTexturePtr}, size={width}x{height}, vulkan={isVulkan}");

        UnityMainThreadDispatcher.Enqueue(() => {
            var renderer = Instance.GetComponent<Renderer>();
            if (renderer == null)
            {
                Debug.LogError("KotlinBridge: No Renderer component found");
                return;
            }

            // Create external texture with actual dimensions from the service
            // Unity handles both OpenGL and Vulkan native textures via CreateExternalTexture
            Texture2D texture = Texture2D.CreateExternalTexture(
                width,
                height,
                TextureFormat.RGBA32,
                false,  // mipChain
                false,  // linear
                nativeTexturePtr
            );

            if (texture == null)
            {
                Debug.LogError("KotlinBridge: Failed to create external texture");
                return;
            }

            // Set texture on material (index 2 is the phone screen material)
            if (renderer.materials.Length > 2)
            {
                renderer.materials[2].mainTexture = texture;
                Debug.Log($"KotlinBridge: Texture set on material[2], {width}x{height}");
            }
            else
            {
                Debug.LogWarning($"KotlinBridge: Not enough materials (have {renderer.materials.Length}, need 3)");
                // Fall back to first material if not enough
                renderer.material.mainTexture = texture;
            }
        });
    }

    void Start()
    {
        Instance = this;

        NativeCallbacks callbacks = new NativeCallbacks();
        callbacks.OnMessage = Marshal.GetFunctionPointerForDelegate(new OnMessageDelegate(OnMessage));
        callbacks.OnServiceInitialized = Marshal.GetFunctionPointerForDelegate(new OnServiceInitializedDelegate(OnServiceInitialized));
        callbacks.OnFrameAvailable = Marshal.GetFunctionPointerForDelegate(new OnFrameAvailableDelegate(OnFrameAvailable));
        callbacks.OnBufferReady = Marshal.GetFunctionPointerForDelegate(new OnBufferReadyDelegate(OnBufferReady));
        callbacks.OnTextureReady = Marshal.GetFunctionPointerForDelegate(new OnTextureReadyDelegate(OnTextureReady));
        SetNativeCallbacks(ref callbacks);

        if (Application.platform == RuntimePlatform.Android)
        {
            using (var ktClass = new AndroidJavaClass("com.omixlab.mosis.unity.MyKotlinPlugin"))
            {
                ktClass.CallStatic("StartMosisService");
            }
        }
    }
}
