using System.Runtime.InteropServices;
using UnityEngine;

/// <summary>
/// Pont de communication entre Unity WebGL et le site parent via window.postMessage.
/// Gère l'échange de tokens JWT pour l'authentification.
/// </summary>
public class PostMessageBridge : MonoBehaviour
{
    #region Singleton
    private static PostMessageBridge _instance;
    private static bool _applicationIsQuitting = false;
    
    public static PostMessageBridge Instance
    {
        get
        {
            // Ne pas créer d'instance si l'application est en train de se fermer
            if (_applicationIsQuitting)
            {
                return null;
            }
            
            if (_instance == null)
            {
                GameObject go = new GameObject("PostMessageBridge");
                _instance = go.AddComponent<PostMessageBridge>();
                DontDestroyOnLoad(go);
            }
            return _instance;
        }
    }
    
    void OnApplicationQuit()
    {
        _applicationIsQuitting = true;
    }
    
    void OnDestroy()
    {
        if (_instance == this)
        {
            _instance = null;
        }
    }
    #endregion

    #region Imports des fonctions JavaScript

#if UNITY_WEBGL && !UNITY_EDITOR
    [DllImport("__Internal")]
    private static extern int PostMessage_Init();

    [DllImport("__Internal")]
    private static extern int PostMessage_IsInIframe();

    [DllImport("__Internal")]
    private static extern int PostMessage_GetToken(System.IntPtr bufferPtr, int bufferSize);

    [DllImport("__Internal")]
    private static extern int PostMessage_HasToken();

    [DllImport("__Internal")]
    private static extern int PostMessage_NotifyLogin(string token);

    [DllImport("__Internal")]
    private static extern void PostMessage_ClearToken();

    [DllImport("__Internal")]
    private static extern int PostMessage_SetToken(string token);

    [DllImport("__Internal")]
    private static extern int PostMessage_SetParentOrigin(string origin);
#else
    // Stubs pour l'éditeur et les autres plateformes
    private static int PostMessage_Init() { return 0; }
    private static int PostMessage_IsInIframe() { return 0; }
    private static int PostMessage_GetToken(System.IntPtr bufferPtr, int bufferSize) { return 0; }
    private static int PostMessage_HasToken() { return 0; }
    private static int PostMessage_NotifyLogin(string token) { return 0; }
    private static void PostMessage_ClearToken() { }
    private static int PostMessage_SetToken(string token) { return 0; }
    private static int PostMessage_SetParentOrigin(string origin) { return 0; }
#endif

    #endregion

    #region Propriétés publiques

    /// <summary>
    /// Indique si le jeu est chargé dans une iframe.
    /// </summary>
    public bool IsInIframe { get; private set; }

    /// <summary>
    /// Indique si un token JWT a été reçu du parent.
    /// </summary>
    public bool HasToken
    {
        get
        {
#if UNITY_WEBGL && !UNITY_EDITOR
            return PostMessage_HasToken() == 1;
#else
            return false;
#endif
        }
    }

    #endregion

    #region Événements

    /// <summary>
    /// Événement déclenché quand un token est reçu du parent.
    /// </summary>
    public event System.Action<string> OnTokenReceived;

    #endregion

    #region Cycle de vie Unity

    void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
            return;
        }

        _instance = this;
        DontDestroyOnLoad(gameObject);

        // Initialiser la communication postMessage
        Initialize();
    }

    #endregion

    #region Méthodes publiques

    /// <summary>
    /// Initialise le système de communication postMessage.
    /// Doit être appelé au démarrage du jeu.
    /// </summary>
    public void Initialize()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        Debug.Log("═══════════════════════════════════════════════════════");
        Debug.Log("[PostMessageBridge] Initialisation de la communication iframe...");
        
        int result = PostMessage_Init();
        Debug.Log($"[PostMessageBridge] PostMessage_Init() retour: {result}");
        
        IsInIframe = PostMessage_IsInIframe() == 1;
        Debug.Log($"[PostMessageBridge] IsInIframe: {IsInIframe}");

        if (result == 1 && IsInIframe)
        {
            Debug.Log("[PostMessageBridge] ✓ Communication iframe activée");
            
            // Vérifier si un token a déjà été reçu
            Debug.Log("[PostMessageBridge] Vérification d'un token existant...");
            CheckForExistingToken();
        }
        else
        {
            Debug.Log("[PostMessageBridge] Jeu non chargé dans une iframe - mode standalone");
        }
        Debug.Log("═══════════════════════════════════════════════════════");
#else
        IsInIframe = false;
        Debug.Log("[PostMessageBridge] Mode éditeur - communication iframe désactivée");
#endif
    }

    /// <summary>
    /// Récupère le token JWT stocké.
    /// </summary>
    /// <returns>Le token JWT ou null si aucun token n'est disponible</returns>
    public string GetToken()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        Debug.Log("[PostMessageBridge] GetToken() appelé");
        
        if (!HasToken)
        {
            Debug.Log("[PostMessageBridge] HasToken = false, retour null");
            return null;
        }

        Debug.Log("[PostMessageBridge] HasToken = true, allocation du buffer...");
        // Allouer un buffer pour recevoir le token
        System.IntPtr buffer = Marshal.AllocHGlobal(2048);
        try
        {
            Debug.Log("[PostMessageBridge] Appel de PostMessage_GetToken()...");
            int result = PostMessage_GetToken(buffer, 2048);
            Debug.Log($"[PostMessageBridge] PostMessage_GetToken() retour: {result}");
            
            if (result == 1)
            {
                string token = Marshal.PtrToStringAnsi(buffer);
                Debug.Log($"[PostMessageBridge] ✓ Token récupéré (longueur: {token?.Length ?? 0})");
                if (!string.IsNullOrEmpty(token))
                {
                    Debug.Log($"[PostMessageBridge] Token (début): {token.Substring(0, System.Math.Min(50, token.Length))}...");
                }
                return token;
            }
            else
            {
                Debug.LogWarning("[PostMessageBridge] PostMessage_GetToken() a retourné 0");
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError($"[PostMessageBridge] Erreur lors de la récupération du token: {e.Message}");
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
#endif
        return null;
    }

    /// <summary>
    /// Envoie un message UJSA_LOGIN au parent après une connexion réussie.
    /// </summary>
    /// <param name="token">Le token JWT à envoyer au parent</param>
    /// <returns>True si le message a été envoyé avec succès</returns>
    public bool NotifyLogin(string token)
    {
        if (string.IsNullOrEmpty(token))
        {
            Debug.LogWarning("[PostMessageBridge] Impossible d'envoyer un token vide");
            return false;
        }

#if UNITY_WEBGL && !UNITY_EDITOR
        if (!IsInIframe)
        {
            Debug.Log("[PostMessageBridge] Pas dans une iframe - notification annulée");
            return false;
        }

        Debug.Log("[PostMessageBridge] Envoi de la notification de login au parent...");
        int result = PostMessage_NotifyLogin(token);
        
        if (result == 1)
        {
            Debug.Log("[PostMessageBridge] ✓ Notification de login envoyée avec succès");
            return true;
        }
        else
        {
            Debug.LogError("[PostMessageBridge] ⛔ Échec de l'envoi de la notification de login");
            return false;
        }
#else
        Debug.Log("[PostMessageBridge] Mode éditeur - notification simulée");
        return true;
#endif
    }

    /// <summary>
    /// Nettoie le token stocké (déconnexion).
    /// </summary>
    public void ClearToken()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        Debug.Log("[PostMessageBridge] Suppression du token JWT");
        PostMessage_ClearToken();
#endif
    }

    /// <summary>
    /// Définit manuellement un token (pour debug ou cas particuliers).
    /// </summary>
    public bool SetToken(string token)
    {
        if (string.IsNullOrEmpty(token))
        {
            return false;
        }

#if UNITY_WEBGL && !UNITY_EDITOR
        Debug.Log("[PostMessageBridge] Définition manuelle du token");
        return PostMessage_SetToken(token) == 1;
#else
        return false;
#endif
    }

    /// <summary>
    /// Change l'origin autorisé du parent (pour environnement de dev).
    /// Par défaut: https://www.newsassurancespro.com
    /// </summary>
    public bool SetParentOrigin(string origin)
    {
        if (string.IsNullOrEmpty(origin))
        {
            return false;
        }

#if UNITY_WEBGL && !UNITY_EDITOR
        Debug.Log($"[PostMessageBridge] Changement de l'origin du parent: {origin}");
        return PostMessage_SetParentOrigin(origin) == 1;
#else
        return false;
#endif
    }

    #endregion

    #region Méthodes privées

    /// <summary>
    /// Vérifie si un token a déjà été reçu lors de l'initialisation.
    /// </summary>
    private void CheckForExistingToken()
    {
        Debug.Log("[PostMessageBridge] CheckForExistingToken() appelé");
        Debug.Log($"[PostMessageBridge] HasToken: {HasToken}");
        
        if (HasToken)
        {
            Debug.Log("[PostMessageBridge] Token détecté, récupération...");
            string token = GetToken();
            Debug.Log($"[PostMessageBridge] Token récupéré: {(string.IsNullOrEmpty(token) ? "VIDE" : $"{token.Length} caractères")}");
            
            if (!string.IsNullOrEmpty(token))
            {
                Debug.Log("[PostMessageBridge] ✓ Token déjà présent lors de l'initialisation");
                Debug.Log($"[PostMessageBridge] Nombre d'abonnés à OnTokenReceived: {OnTokenReceived?.GetInvocationList().Length ?? 0}");
                OnTokenReceived?.Invoke(token);
                Debug.Log("[PostMessageBridge] Événement OnTokenReceived déclenché");
            }
        }
        else
        {
            Debug.Log("[PostMessageBridge] Aucun token présent pour le moment");
        }
    }

    /// <summary>
    /// Callback appelé par JavaScript quand un token est reçu du parent.
    /// Cette méthode est appelée via SendMessage depuis le .jslib.
    /// IMPORTANT: Le GameObject doit s'appeler "LoginManager" pour recevoir ce callback,
    /// ou vous pouvez renommer dans le .jslib (ligne: SendMessage('LoginManager', 'OnTokenReceived', data.token))
    /// </summary>
    /// <param name="token">Le token JWT reçu</param>
    public void OnTokenReceivedFromJS(string token)
    {
        Debug.Log($"[PostMessageBridge] Token reçu depuis JavaScript (longueur: {token?.Length ?? 0})");
        
        if (!string.IsNullOrEmpty(token))
        {
            OnTokenReceived?.Invoke(token);
        }
    }

    #endregion
}

