// ==============================================
// AuthManager.cs - Unity Auth Handler
// ==============================================
// Handles JWT token for Keycloak authentication.
// Supports token via URL parameter or PostMessage from parent frame.

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

namespace BreakpilotDrive
{
    public class AuthManager : MonoBehaviour
    {
        public static AuthManager Instance { get; private set; }

        [Header("Auth Configuration")]
        [SerializeField] private bool requireAuth = false;
        [SerializeField] private string devUserId = "dev-user-123";

        // Current auth state
        private string jwtToken;
        private string userId;
        private bool isAuthenticated;

        // Events
        public event Action<string> OnAuthenticated;
        public event Action<string> OnAuthFailed;

        // JavaScript interface for WebGL
#if UNITY_WEBGL && !UNITY_EDITOR
        [DllImport("__Internal")]
        private static extern string GetTokenFromURL();

        [DllImport("__Internal")]
        private static extern string GetTokenFromParent();

        [DllImport("__Internal")]
        private static extern void RequestTokenFromParent();
#endif

        void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
            }
        }

        void Start()
        {
            InitializeAuth();
        }

        // ==============================================
        // Initialization
        // ==============================================

        private void InitializeAuth()
        {
            // Development mode - use dev user
            if (!requireAuth || Application.isEditor)
            {
                SetDevUser();
                return;
            }

#if UNITY_WEBGL && !UNITY_EDITOR
            // Try URL parameter first
            string urlToken = GetTokenFromURL();
            if (!string.IsNullOrEmpty(urlToken))
            {
                SetToken(urlToken);
                return;
            }

            // Try parent frame (iframe scenario)
            RequestTokenFromParent();
#else
            // Non-WebGL builds use dev user
            SetDevUser();
#endif
        }

        private void SetDevUser()
        {
            userId = devUserId;
            isAuthenticated = true;
            jwtToken = null;

            Debug.Log($"[Auth] Development mode - User: {userId}");
            OnAuthenticated?.Invoke(userId);
        }

        // ==============================================
        // Token Management
        // ==============================================

        public void SetToken(string token)
        {
            if (string.IsNullOrEmpty(token))
            {
                OnAuthFailed?.Invoke("Empty token");
                return;
            }

            jwtToken = token;
            userId = ExtractUserIdFromToken(token);

            if (!string.IsNullOrEmpty(userId))
            {
                isAuthenticated = true;
                Debug.Log($"[Auth] Authenticated - User: {userId}");
                OnAuthenticated?.Invoke(userId);
            }
            else
            {
                OnAuthFailed?.Invoke("Could not extract user ID from token");
            }
        }

        // Called from JavaScript via SendMessage
        public void ReceiveTokenFromJS(string token)
        {
            Debug.Log("[Auth] Received token from JavaScript");
            SetToken(token);
        }

        // Called from JavaScript if auth fails
        public void AuthFailedFromJS(string error)
        {
            Debug.LogWarning($"[Auth] JavaScript auth failed: {error}");

            // Fall back to dev user in development
            if (!requireAuth)
            {
                SetDevUser();
            }
            else
            {
                OnAuthFailed?.Invoke(error);
            }
        }

        private string ExtractUserIdFromToken(string token)
        {
            try
            {
                // JWT has 3 parts: header.payload.signature
                string[] parts = token.Split('.');
                if (parts.Length != 3) return null;

                // Decode payload (base64)
                string payload = parts[1];

                // Fix base64 padding
                int padding = 4 - (payload.Length % 4);
                if (padding < 4) payload += new string('=', padding);

                // Replace URL-safe chars
                payload = payload.Replace('-', '+').Replace('_', '/');

                byte[] bytes = Convert.FromBase64String(payload);
                string json = System.Text.Encoding.UTF8.GetString(bytes);

                // Simple JSON parsing for "sub" claim
                var claims = JsonUtility.FromJson<JWTPayload>(json);
                return claims?.sub;
            }
            catch (Exception e)
            {
                Debug.LogWarning($"[Auth] Token parsing failed: {e.Message}");
                return null;
            }
        }

        [Serializable]
        private class JWTPayload
        {
            public string sub;
            public string email;
            public string name;
            public long exp;
            public long iat;
        }

        // ==============================================
        // Public API
        // ==============================================

        public bool IsAuthenticated => isAuthenticated;
        public string UserId => userId;
        public string Token => jwtToken;
        public bool RequiresAuth => requireAuth;

        public string GetAuthHeader()
        {
            if (string.IsNullOrEmpty(jwtToken))
                return null;
            return $"Bearer {jwtToken}";
        }

        public void Logout()
        {
            jwtToken = null;
            userId = null;
            isAuthenticated = false;
            Debug.Log("[Auth] Logged out");
        }

        // Check if token is expired
        public bool IsTokenExpired()
        {
            if (string.IsNullOrEmpty(jwtToken))
                return true;

            try
            {
                string[] parts = jwtToken.Split('.');
                if (parts.Length != 3) return true;

                string payload = parts[1];
                int padding = 4 - (payload.Length % 4);
                if (padding < 4) payload += new string('=', padding);
                payload = payload.Replace('-', '+').Replace('_', '/');

                byte[] bytes = Convert.FromBase64String(payload);
                string json = System.Text.Encoding.UTF8.GetString(bytes);
                var claims = JsonUtility.FromJson<JWTPayload>(json);

                if (claims?.exp > 0)
                {
                    var expTime = DateTimeOffset.FromUnixTimeSeconds(claims.exp).UtcDateTime;
                    return DateTime.UtcNow > expTime;
                }
            }
            catch { }

            return false;
        }
    }
}
