using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

/// <summary>
/// Gestionnaire de l'authentification via iframe.
/// Orchestre la communication postMessage entre Unity et le site parent.
/// </summary>
public class IframeAuthManager : MonoBehaviour
{
    #region Singleton
    private static IframeAuthManager _instance;
    public static IframeAuthManager Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject("IframeAuthManager");
                _instance = go.AddComponent<IframeAuthManager>();
                DontDestroyOnLoad(go);
            }
            return _instance;
        }
    }
    #endregion

    #region Propriétés

    /// <summary>
    /// Indique si l'authentification via iframe est active.
    /// </summary>
    public bool IsIframeAuthActive => PostMessageBridge.Instance.IsInIframe;

    /// <summary>
    /// Indique si l'utilisateur a été authentifié via le token iframe.
    /// </summary>
    public bool IsAuthenticatedViaIframe { get; private set; }
    
    /// <summary>
    /// Indique si une authentification est en cours (évite les appels multiples).
    /// </summary>
    public bool IsAuthenticating { get; private set; } = false;

    #endregion

    /// <summary>
    /// Réinitialise l'état d'auth iframe (utile lors d'une déconnexion manuelle).
    /// Sans ça, la scène Main peut croire qu'on est encore "authentifié via iframe" et ne pas afficher la popup.
    /// </summary>
    public void ResetAuthState()
    {
        Debug.Log("[IframeAuth] 🔄 ResetAuthState() - reset flags + stop coroutines");
        try { StopAllCoroutines(); } catch { }
        IsAuthenticatedViaIframe = false;
        IsAuthenticating = false;
    }

    #region Cycle de vie Unity

    void Awake()
    {
        Debug.Log("═══════════════════════════════════════════════════════");
        Debug.Log("[IframeAuth] Awake() appelé");
        
        if (_instance != null && _instance != this)
        {
            Debug.Log("[IframeAuth] Instance déjà existante, destruction de ce GameObject");
            Destroy(gameObject);
            return;
        }

        _instance = this;
        DontDestroyOnLoad(gameObject);
        Debug.Log("[IframeAuth] Instance créée et marquée DontDestroyOnLoad");

        // S'abonner à l'événement de réception de token
        Debug.Log("[IframeAuth] Abonnement à PostMessageBridge.OnTokenReceived");
        PostMessageBridge.Instance.OnTokenReceived += OnTokenReceivedFromParent;
        Debug.Log("[IframeAuth] ✓ Abonnement effectué");
        
        // Vérifier immédiatement s'il y a un token en attente (arrivé avant l'abonnement)
        CheckForPendingToken();
        Debug.Log("═══════════════════════════════════════════════════════");
    }

    void Start()
    {
        Debug.Log("═══════════════════════════════════════════════════════");
        Debug.Log("[IframeAuth] Start() appelé");
        
        // NOTE IMPORTANTE : 
        // L'origin autorisé est configuré par défaut à "https://www.newsassurancespro.com"
        // dans le fichier .jslib. Pour les tests, vous pouvez le changer manuellement
        // en appelant PostMessageBridge.Instance.SetParentOrigin("https://votre-domaine-test.com")
        // depuis un autre script ou via la console Unity.
        
        // Vérifier au démarrage s'il y a un token du parent (via HasToken JS)
        CheckForParentToken();
        
        // Re-vérifier le token en attente au cas où il serait arrivé entre Awake et Start
        CheckForPendingToken();
        Debug.Log("═══════════════════════════════════════════════════════");
    }
    
    /// <summary>
    /// Vérifie s'il y a un token en attente dans PostMessageBridge (arrivé avant l'abonnement).
    /// </summary>
    private void CheckForPendingToken()
    {
        // Si déjà connecté, pas besoin de vérifier
        if (UserDataManager.Instance != null && UserDataManager.Instance.IsLoggedIn())
        {
            Debug.Log("[IframeAuth] Utilisateur déjà connecté - vérification du token en attente ignorée");
            if (PostMessageBridge.Instance.HasPendingToken)
            {
                PostMessageBridge.Instance.ClearPendingToken();
            }
            return;
        }
        
        if (PostMessageBridge.Instance.HasPendingToken)
        {
            string pendingToken = PostMessageBridge.Instance.PendingToken;
            Debug.Log($"[IframeAuth] 📨 Token en attente trouvé ! (longueur: {pendingToken?.Length ?? 0})");
            
            // Traiter le token en attente (cette méthode clear aussi le pending token)
            OnTokenReceivedFromParent(pendingToken);
        }
        else
        {
            Debug.Log("[IframeAuth] Aucun token en attente");
        }
    }

    void OnDestroy()
    {
        if (_instance == this)
        {
            // Se désabonner de l'événement (vérifier que l'instance existe et que l'app ne se ferme pas)
            var bridge = PostMessageBridge.Instance;
            if (bridge != null)
            {
                bridge.OnTokenReceived -= OnTokenReceivedFromParent;
            }
            _instance = null;
        }
    }

    #endregion

    #region Méthodes publiques

    /// <summary>
    /// Vérifie s'il y a un token reçu du parent et tente une authentification.
    /// </summary>
    public void CheckForParentToken()
    {
        Debug.Log("[IframeAuth] ─────────────────────────────────────────");
        Debug.Log("[IframeAuth] CheckForParentToken() appelé");
        Debug.Log($"[IframeAuth] PostMessageBridge.Instance.IsInIframe: {PostMessageBridge.Instance.IsInIframe}");
        
        if (!PostMessageBridge.Instance.IsInIframe)
        {
            Debug.Log("[IframeAuth] ⚠ Pas dans une iframe - authentification standard");
            return;
        }

        Debug.Log("[IframeAuth] ✓ Dans une iframe - vérification du token parent...");

        // Vérifier si un token existe déjà dans UserDataManager (session précédente)
        Debug.Log("[IframeAuth] Vérification de UserDataManager...");
        if (UserDataManager.Instance != null)
        {
            Debug.Log($"[IframeAuth] UserDataManager.Instance existe");
            bool isLoggedIn = UserDataManager.Instance.IsLoggedIn();
            Debug.Log($"[IframeAuth] UserDataManager.Instance.IsLoggedIn(): {isLoggedIn}");
            
            if (isLoggedIn)
            {
                Debug.Log("[IframeAuth] ✓ Utilisateur déjà authentifié (session existante)");
                IsAuthenticatedViaIframe = false; // Pas via iframe, session locale
                return;
            }
        }
        else
        {
            Debug.LogWarning("[IframeAuth] UserDataManager.Instance est null !");
        }

        // Vérifier si un token a été reçu du parent
        Debug.Log("[IframeAuth] Vérification du token parent...");
        bool hasToken = PostMessageBridge.Instance.HasToken;
        Debug.Log($"[IframeAuth] PostMessageBridge.Instance.HasToken: {hasToken}");
        
        if (hasToken)
        {
            Debug.Log("[IframeAuth] ✓ Token détecté, récupération...");
            string token = PostMessageBridge.Instance.GetToken();
            Debug.Log($"[IframeAuth] Token récupéré: {(string.IsNullOrEmpty(token) ? "VIDE OU NULL" : $"{token.Length} caractères")}");
            
            if (!string.IsNullOrEmpty(token))
            {
                Debug.Log("[IframeAuth] 🔐 Démarrage de l'authentification avec le token parent...");
                StartCoroutine(AuthenticateWithToken(token));
            }
            else
            {
                Debug.LogWarning("[IframeAuth] ⚠ Token vide ou null malgré HasToken = true");
            }
        }
        else
        {
            Debug.Log("[IframeAuth] ⚠ Aucun token reçu du parent - attente ou login standard");
        }
        Debug.Log("[IframeAuth] ─────────────────────────────────────────");
    }

    /// <summary>
    /// Notifie le parent qu'une connexion a été effectuée avec succès.
    /// À appeler après une connexion réussie via le formulaire de login.
    /// </summary>
    public void NotifyParentOfLogin()
    {
        if (!PostMessageBridge.Instance.IsInIframe)
        {
            Debug.Log("[IframeAuth] Pas dans une iframe - notification ignorée");
            return;
        }

        if (UserDataManager.Instance == null || !UserDataManager.Instance.IsLoggedIn())
        {
            Debug.LogWarning("[IframeAuth] Impossible de notifier : utilisateur non connecté");
            return;
        }

        string token = UserDataManager.Instance.token;
        if (string.IsNullOrEmpty(token))
        {
            Debug.LogWarning("[IframeAuth] Impossible de notifier : token vide");
            return;
        }

        Debug.Log("[IframeAuth] Notification du parent suite à la connexion...");
        bool success = PostMessageBridge.Instance.NotifyLogin(token);

        if (success)
        {
            Debug.Log("[IframeAuth] ✓ Parent notifié avec succès");
        }
        else
        {
            Debug.LogError("[IframeAuth] ⛔ Échec de la notification du parent");
        }
    }

    #endregion

    #region Méthodes privées

    /// <summary>
    /// Callback appelé quand un token est reçu du parent.
    /// </summary>
    private void OnTokenReceivedFromParent(string token)
    {
        Debug.Log("═══════════════════════════════════════════════════════");
        Debug.Log("[IframeAuth] 📨 OnTokenReceivedFromParent() CALLBACK DÉCLENCHÉ !");
        Debug.Log($"[IframeAuth] Token reçu du parent (callback) - longueur: {token?.Length ?? 0}");
        
        if (string.IsNullOrEmpty(token))
        {
            Debug.LogWarning("[IframeAuth] ⚠ Token vide ou null dans le callback");
            return;
        }
        
        // Marquer le token comme traité pour éviter les doublons
        if (PostMessageBridge.Instance.HasPendingToken && PostMessageBridge.Instance.PendingToken == token)
        {
            PostMessageBridge.Instance.ClearPendingToken();
        }

        // Si l'utilisateur est déjà connecté, ignorer le nouveau token
        if (UserDataManager.Instance != null && UserDataManager.Instance.IsLoggedIn())
        {
            Debug.Log("[IframeAuth] Utilisateur déjà connecté - token parent ignoré");
            return;
        }
        
        // Si une authentification est déjà en cours, ignorer
        if (IsAuthenticating)
        {
            Debug.Log("[IframeAuth] Authentification déjà en cours - token ignoré");
            return;
        }

        // Tenter l'authentification avec ce token
        Debug.Log("[IframeAuth] 🔐 Démarrage de l'authentification avec le token reçu...");
        StartCoroutine(AuthenticateWithToken(token));
        Debug.Log("═══════════════════════════════════════════════════════");
    }

    /// <summary>
    /// Authentifie l'utilisateur avec un token JWT reçu du parent.
    /// </summary>
    private IEnumerator AuthenticateWithToken(string token)
    {
        // Vérifier si une authentification est déjà en cours
        if (IsAuthenticating)
        {
            Debug.Log("[IframeAuth] Authentification déjà en cours - abandon");
            yield break;
        }
        
        IsAuthenticating = true;
        
        Debug.Log("═══════════════════════════════════════════════════════");
        Debug.Log("[IframeAuth] 🔐 AuthenticateWithToken() DÉMARRÉ");
        Debug.Log($"[IframeAuth] Token (longueur): {token?.Length ?? 0}");
        Debug.Log($"[IframeAuth] Token (début): {(string.IsNullOrEmpty(token) ? "VIDE" : token.Substring(0, System.Math.Min(50, token.Length)))}...");

        // Récupérer l'URL de base de l'API
        Debug.Log("[IframeAuth] Récupération de l'URL de base de l'API...");
        string apiBaseUrl = GeneralConfigManager.Instance?.GetApiBaseUrl() ?? "";
        
        if (string.IsNullOrEmpty(apiBaseUrl))
        {
            Debug.LogError("[IframeAuth] ⛔ URL de base de l'API non définie dans general-config.json");
            Debug.Log("═══════════════════════════════════════════════════════");
            IsAuthenticating = false;
            yield break;
        }
        
        string verifyUrl = $"{apiBaseUrl}/api/ujsa/user";
        Debug.Log($"[IframeAuth] ✓ URL de vérification: {verifyUrl}");

        // Préparer la requête avec le token en en-tête Authorization
        Debug.Log($"[IframeAuth] Création de la requête GET vers: {verifyUrl}");
        using (UnityWebRequest www = UnityWebRequest.Get(verifyUrl))
        {
            string tokenPreview = token.Substring(0, System.Math.Min(50, token.Length));
            Debug.Log($"[IframeAuth] Ajout du header Authorization: Bearer {tokenPreview}...");
            www.SetRequestHeader("Authorization", $"Bearer {token}");
            www.SetRequestHeader("Content-Type", "application/json");
            www.SetRequestHeader("Accept", "application/json");
            
            // Log des headers pour debug
            Debug.Log($"[IframeAuth] Headers de la requête:");
            Debug.Log($"[IframeAuth]   - Authorization: Bearer {tokenPreview}...");
            Debug.Log($"[IframeAuth]   - Content-Type: application/json");
            Debug.Log($"[IframeAuth]   - Accept: application/json");

            Debug.Log("[IframeAuth] Envoi de la requête...");
            yield return www.SendWebRequest();

            Debug.Log($"[IframeAuth] Requête terminée - Result: {www.result}");
            Debug.Log($"[IframeAuth] Code HTTP: {www.responseCode}");

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"[IframeAuth] ⛔ Échec de la vérification du token: {www.error}");
                Debug.LogError($"[IframeAuth] Code HTTP: {www.responseCode}");
                string responseText = www.downloadHandler?.text ?? "VIDE";
                Debug.LogError($"[IframeAuth] Réponse: {responseText}");
                
                // Ne pas nettoyer le token si c'est une erreur serveur (erreurs temporaires)
                // 500 = Internal Server Error, 502 = Bad Gateway, 503 = Service Unavailable, 504 = Gateway Timeout
                bool isServerError = www.responseCode >= 500 && www.responseCode < 600;
                
                if (isServerError)
                {
                    Debug.LogWarning($"[IframeAuth] ⚠ Erreur serveur ({www.responseCode}) - token conservé pour réessai ultérieur");
                    // Ne pas nettoyer le token, il pourrait être valide mais le serveur a un problème temporaire
                }
                else
                {
                    // Erreur client (401, 403, etc.) = token invalide
                    Debug.Log("[IframeAuth] Nettoyage du token (erreur client)...");
                    PostMessageBridge.Instance.ClearToken();
                }
                
                Debug.Log("═══════════════════════════════════════════════════════");
                IsAuthenticating = false;
                yield break;
            }

            // Parser la réponse
            string jsonResponse = www.downloadHandler.text;
            Debug.Log($"[IframeAuth] ✓ Réponse du serveur reçue ({jsonResponse.Length} caractères)");
            Debug.Log($"[IframeAuth] Réponse JSON: {jsonResponse}");

            try
            {
                Debug.Log("[IframeAuth] Parsing de la réponse JSON...");
                UserDataManager.UserApiResponse response = JsonUtility.FromJson<UserDataManager.UserApiResponse>(jsonResponse);

                Debug.Log($"[IframeAuth] Response parsée - status: {response?.status ?? "NULL"}");
                Debug.Log($"[IframeAuth] Response.data: {(response?.data != null ? "PRÉSENT" : "NULL")}");

                if (response != null && response.status == "success" && response.data != null)
                {
                    Debug.Log("[IframeAuth] ✓✓✓ Token valide - authentification réussie ✓✓✓");
                    Debug.Log($"[IframeAuth] Email: {response.data.email}");
                    Debug.Log($"[IframeAuth] Nom: {response.data.first_name} {response.data.last_name}");

                    // Stocker les données utilisateur
                    if (UserDataManager.Instance != null)
                    {
                        Debug.Log("[IframeAuth] Conversion des données pour UserDataManager...");
                        // Convertir UserApiData en LoginResponseData
                        // Note: UserApiData n'a pas tous les champs de LoginResponseData, on utilise des valeurs par défaut
                        LoginResponseData loginData = new LoginResponseData
                        {
                            token = token,
                            user_id = 0, // Non disponible dans UserApiData, sera mis à jour par LoadUserDataFromApi
                            email = response.data.email ?? "",
                            is_napro_membership = false, // Non disponible dans UserApiData
                            is_cl_membership = false, // Non disponible dans UserApiData
                            is_annie_membership = false, // Non disponible dans UserApiData
                            is_ujsa_membership = response.data.has_membership, // Mapper has_membership vers is_ujsa_membership
                            email_validated = true, // On suppose validé si l'API répond avec succès
                            profil_completed = false, // Non disponible dans UserApiData
                            about_me = "", // Non disponible dans UserApiData
                            company = !string.IsNullOrEmpty(response.data.company) ? new CompanyInfo
                            {
                                id = 0, // Non disponible dans UserApiData
                                name = response.data.company
                            } : null
                        };

                        Debug.Log("[IframeAuth] Stockage des données utilisateur...");
                        UserDataManager.Instance.StoreUserData(loginData);
                        IsAuthenticatedViaIframe = true;

                        Debug.Log("[IframeAuth] ✓✓✓ Données utilisateur stockées avec succès ✓✓✓");
                        Debug.Log($"[IframeAuth] IsAuthenticatedViaIframe: {IsAuthenticatedViaIframe}");
                        
                        // Recharger la configuration du projet depuis l'API avec le token utilisateur
                        MainSceneManager mainSceneManager = FindFirstObjectByType<MainSceneManager>();
                        if (mainSceneManager != null)
                        {
                            Debug.Log("[IframeAuth] 🔄 Déclenchement du rafraîchissement de la configuration du projet...");
                            mainSceneManager.RefreshProjectConfiguration();
                        }
                        else
                        {
                            Debug.Log("[IframeAuth] ⚠️ MainSceneManager non trouvé - rafraîchissement ignoré (scène Main pas active)");
                        }
                    }
                    else
                    {
                        Debug.LogError("[IframeAuth] ⛔ UserDataManager.Instance est NULL !");
                    }
                }
                else
                {
                    Debug.LogError("[IframeAuth] ⛔ Token invalide ou réponse incorrecte");
                    Debug.LogError($"[IframeAuth] Status: {response?.status}");
                    Debug.LogError($"[IframeAuth] Message: {response?.message}");
                    PostMessageBridge.Instance.ClearToken();
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError($"[IframeAuth] ⛔ Erreur lors du parsing de la réponse: {e.Message}");
                Debug.LogError($"[IframeAuth] Stack trace: {e.StackTrace}");
                Debug.LogError($"[IframeAuth] Réponse reçue: {jsonResponse}");
                PostMessageBridge.Instance.ClearToken();
            }
        }
        
        IsAuthenticating = false;
        Debug.Log("═══════════════════════════════════════════════════════");
    }

    #endregion
}

// Note: Les classes UserApiResponse et UserApiData sont définies dans UserDataManager.cs

