// ==============================================
// BreakpilotAPI.cs - Unity API Client
// ==============================================
// Kopiere diese Datei nach Assets/Scripts/Network/
// um mit dem Breakpilot Backend zu kommunizieren.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

namespace BreakpilotDrive
{
    [Serializable]
    public class LearningLevel
    {
        public string user_id;
        public int overall_level;
        public float math_level;
        public float german_level;
        public float english_level;
    }

    [Serializable]
    public class GameDifficulty
    {
        public float lane_speed;
        public float obstacle_frequency;
        public float power_up_chance;
        public int question_complexity;
        public int answer_time;
        public bool hints_enabled;
        public float speech_speed;
    }

    [Serializable]
    public class QuizQuestion
    {
        public string id;
        public string question_text;
        public string audio_url;
        public string[] options;
        public int correct_index;
        public int difficulty;
        public string subject;
        public int grade_level;
        public string quiz_mode; // "quick" oder "pause"
        public string visual_trigger; // z.B. "bridge"
        public float time_limit_seconds;
    }

    [Serializable]
    public class QuizQuestionList
    {
        public QuizQuestion[] questions;
    }

    [Serializable]
    public class GameSession
    {
        public string user_id;
        public string game_mode; // "video" oder "audio"
        public int duration_seconds;
        public float distance_traveled;
        public int score;
        public int questions_answered;
        public int questions_correct;
        public int difficulty_level;
    }

    [Serializable]
    public class SessionResponse
    {
        public string session_id;
        public string status;
        public int? new_level;
    }

    [Serializable]
    public class VisualTrigger
    {
        public string trigger;
        public int question_count;
        public int[] difficulties;
        public string[] subjects;
    }

    [Serializable]
    public class ProgressData
    {
        public string date;
        public int sessions;
        public int total_score;
        public int questions;
        public int correct;
        public float accuracy;
        public float avg_difficulty;
    }

    [Serializable]
    public class ProgressResponse
    {
        public string user_id;
        public int days;
        public int data_points;
        public ProgressData[] progress;
    }

    [Serializable]
    public class LeaderboardEntry
    {
        public int rank;
        public string user_id;
        public int total_score;
        public string display_name;
    }

    public class BreakpilotAPI : MonoBehaviour
    {
        // Singleton Pattern
        public static BreakpilotAPI Instance { get; private set; }

        [Header("API Konfiguration")]
        [SerializeField] private string baseUrl = "http://localhost:8000/api/game";
        [SerializeField] private bool useOfflineCache = true;

        // Cached Data
        private LearningLevel cachedLevel;
        private GameDifficulty cachedDifficulty;
        private List<QuizQuestion> cachedQuestions = new List<QuizQuestion>();
        private List<VisualTrigger> cachedTriggers = new List<VisualTrigger>();

        // API URL property (for other scripts)
        public string BaseUrl => baseUrl;

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

        // ==============================================
        // Helper: Add Auth Header to Request
        // ==============================================
        private void AddAuthHeader(UnityWebRequest request)
        {
            if (AuthManager.Instance != null)
            {
                string authHeader = AuthManager.Instance.GetAuthHeader();
                if (!string.IsNullOrEmpty(authHeader))
                {
                    request.SetRequestHeader("Authorization", authHeader);
                }
            }
        }

        // Get current user ID (from auth or fallback)
        public string GetCurrentUserId()
        {
            if (AuthManager.Instance != null && AuthManager.Instance.IsAuthenticated)
            {
                return AuthManager.Instance.UserId;
            }
            return "anonymous";
        }

        // ==============================================
        // Lernniveau abrufen
        // ==============================================
        public IEnumerator GetLearningLevel(string userId, Action<LearningLevel> onSuccess, Action<string> onError = null)
        {
            string url = $"{baseUrl}/learning-level/{userId}";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    LearningLevel level = JsonUtility.FromJson<LearningLevel>(request.downloadHandler.text);
                    cachedLevel = level;
                    onSuccess?.Invoke(level);
                }
                else
                {
                    Debug.LogWarning($"API Fehler: {request.error}");

                    // Offline-Fallback
                    if (useOfflineCache && cachedLevel != null)
                    {
                        onSuccess?.Invoke(cachedLevel);
                    }
                    else
                    {
                        // Standard-Level
                        onSuccess?.Invoke(new LearningLevel { user_id = userId, overall_level = 3 });
                    }

                    onError?.Invoke(request.error);
                }
            }
        }

        // ==============================================
        // Schwierigkeit abrufen
        // ==============================================
        public IEnumerator GetDifficulty(int level, Action<GameDifficulty> onSuccess, Action<string> onError = null)
        {
            string url = $"{baseUrl}/difficulty/{level}";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    GameDifficulty difficulty = JsonUtility.FromJson<GameDifficulty>(request.downloadHandler.text);
                    cachedDifficulty = difficulty;
                    onSuccess?.Invoke(difficulty);
                }
                else
                {
                    Debug.LogWarning($"API Fehler: {request.error}");

                    // Fallback: Default-Schwierigkeit
                    if (cachedDifficulty != null)
                    {
                        onSuccess?.Invoke(cachedDifficulty);
                    }
                    else
                    {
                        onSuccess?.Invoke(GetDefaultDifficulty(level));
                    }

                    onError?.Invoke(request.error);
                }
            }
        }

        // ==============================================
        // Quiz-Fragen abrufen
        // ==============================================
        public IEnumerator GetQuizQuestions(
            int difficulty,
            int count,
            string mode = null, // "quick", "pause", oder null fuer beide
            string subject = null,
            Action<QuizQuestion[]> onSuccess = null,
            Action<string> onError = null)
        {
            string url = $"{baseUrl}/quiz/questions?difficulty={difficulty}&count={count}";
            if (!string.IsNullOrEmpty(mode)) url += $"&mode={mode}";
            if (!string.IsNullOrEmpty(subject)) url += $"&subject={subject}";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    // Unity's JsonUtility braucht Wrapper fuer Arrays
                    string wrappedJson = "{\"questions\":" + request.downloadHandler.text + "}";
                    QuizQuestionList list = JsonUtility.FromJson<QuizQuestionList>(wrappedJson);

                    // Cache updaten
                    if (list.questions != null)
                    {
                        cachedQuestions.AddRange(list.questions);
                    }

                    onSuccess?.Invoke(list.questions);
                }
                else
                {
                    Debug.LogWarning($"API Fehler: {request.error}");

                    // Offline-Fallback
                    if (useOfflineCache && cachedQuestions.Count > 0)
                    {
                        var filtered = cachedQuestions.FindAll(q =>
                            Math.Abs(q.difficulty - difficulty) <= 1 &&
                            (string.IsNullOrEmpty(mode) || q.quiz_mode == mode)
                        );
                        onSuccess?.Invoke(filtered.GetRange(0, Math.Min(count, filtered.Count)).ToArray());
                    }

                    onError?.Invoke(request.error);
                }
            }
        }

        // ==============================================
        // Visuelle Trigger abrufen
        // ==============================================
        public IEnumerator GetVisualTriggers(Action<VisualTrigger[]> onSuccess, Action<string> onError = null)
        {
            string url = $"{baseUrl}/quiz/visual-triggers";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    // Parse Array
                    string wrappedJson = "{\"triggers\":" + request.downloadHandler.text + "}";
                    VisualTriggersWrapper wrapper = JsonUtility.FromJson<VisualTriggersWrapper>(wrappedJson);
                    cachedTriggers = new List<VisualTrigger>(wrapper.triggers);
                    onSuccess?.Invoke(wrapper.triggers);
                }
                else
                {
                    Debug.LogWarning($"API Fehler: {request.error}");
                    onError?.Invoke(request.error);
                }
            }
        }

        [Serializable]
        private class VisualTriggersWrapper
        {
            public VisualTrigger[] triggers;
        }

        // ==============================================
        // Spielsession speichern
        // ==============================================
        public IEnumerator SaveGameSession(GameSession session, Action<SessionResponse> onSuccess = null, Action<string> onError = null)
        {
            string url = $"{baseUrl}/session";
            string json = JsonUtility.ToJson(session);

            using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
            {
                byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json);
                request.uploadHandler = new UploadHandlerRaw(bodyRaw);
                request.downloadHandler = new DownloadHandlerBuffer();
                request.SetRequestHeader("Content-Type", "application/json");

                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    SessionResponse response = JsonUtility.FromJson<SessionResponse>(request.downloadHandler.text);
                    onSuccess?.Invoke(response);

                    // Bei Level-Aenderung cachedLevel updaten
                    if (response.new_level.HasValue && cachedLevel != null)
                    {
                        cachedLevel.overall_level = response.new_level.Value;
                    }
                }
                else
                {
                    Debug.LogWarning($"Session speichern fehlgeschlagen: {request.error}");

                    // Offline: Spaeter synchronisieren
                    if (useOfflineCache)
                    {
                        QueueOfflineSession(session);
                    }

                    onError?.Invoke(request.error);
                }
            }
        }

        // ==============================================
        // Offline-Handling
        // ==============================================
        private List<GameSession> offlineSessions = new List<GameSession>();

        private void QueueOfflineSession(GameSession session)
        {
            offlineSessions.Add(session);
            // Spaeter: PlayerPrefs oder lokale DB nutzen
            Debug.Log($"Session zur Offline-Queue hinzugefuegt. Queue-Groesse: {offlineSessions.Count}");
        }

        public IEnumerator SyncOfflineSessions()
        {
            var sessionsToSync = new List<GameSession>(offlineSessions);
            offlineSessions.Clear();

            foreach (var session in sessionsToSync)
            {
                yield return SaveGameSession(session,
                    onSuccess: (response) => Debug.Log($"Offline-Session synchronisiert: {response.session_id}"),
                    onError: (error) => offlineSessions.Add(session) // Zurueck in Queue
                );
            }
        }

        // ==============================================
        // Helper
        // ==============================================
        private GameDifficulty GetDefaultDifficulty(int level)
        {
            // Fallback-Werte wenn API nicht erreichbar
            return new GameDifficulty
            {
                lane_speed = 3f + level,
                obstacle_frequency = 0.3f + (level * 0.1f),
                power_up_chance = 0.4f - (level * 0.05f),
                question_complexity = level,
                answer_time = 15 - (level * 2),
                hints_enabled = level <= 3,
                speech_speed = 0.8f + (level * 0.1f)
            };
        }

        // ==============================================
        // Frage fuer visuellen Trigger holen
        // ==============================================
        public QuizQuestion GetQuestionForTrigger(string triggerType, int difficulty)
        {
            var matching = cachedQuestions.FindAll(q =>
                q.quiz_mode == "quick" &&
                q.visual_trigger == triggerType &&
                Math.Abs(q.difficulty - difficulty) <= 1
            );

            if (matching.Count > 0)
            {
                return matching[UnityEngine.Random.Range(0, matching.Count)];
            }

            return null;
        }

        // ==============================================
        // Cache-Zugriff
        // ==============================================
        public LearningLevel GetCachedLevel()
        {
            return cachedLevel;
        }

        public List<QuizQuestion> GetCachedQuestions()
        {
            return cachedQuestions;
        }

        public GameDifficulty GetCachedDifficulty()
        {
            return cachedDifficulty;
        }

        public int GetCachedQuestionsCount()
        {
            return cachedQuestions.Count;
        }

        public void ClearQuestionCache()
        {
            cachedQuestions.Clear();
        }

        // ==============================================
        // Progress API (Phase 5)
        // ==============================================
        public IEnumerator GetProgress(
            string userId,
            int days,
            Action<ProgressResponse> onSuccess,
            Action<string> onError = null)
        {
            string url = $"{baseUrl}/progress/{userId}?days={days}";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                AddAuthHeader(request);
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    var response = JsonUtility.FromJson<ProgressResponse>(request.downloadHandler.text);
                    onSuccess?.Invoke(response);
                }
                else
                {
                    Debug.LogWarning($"Progress API error: {request.error}");
                    onError?.Invoke(request.error);
                }
            }
        }

        // ==============================================
        // Leaderboard API (Phase 5)
        // ==============================================
        public IEnumerator GetLeaderboard(
            string timeframe,
            int limit,
            bool anonymize,
            Action<LeaderboardEntry[]> onSuccess,
            Action<string> onError = null)
        {
            string url = $"{baseUrl}/leaderboard/display?timeframe={timeframe}&limit={limit}&anonymize={anonymize.ToString().ToLower()}";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    string wrappedJson = "{\"entries\":" + request.downloadHandler.text + "}";
                    var wrapper = JsonUtility.FromJson<LeaderboardWrapper>(wrappedJson);
                    onSuccess?.Invoke(wrapper.entries);
                }
                else
                {
                    Debug.LogWarning($"Leaderboard API error: {request.error}");
                    onError?.Invoke(request.error);
                }
            }
        }

        [Serializable]
        private class LeaderboardWrapper
        {
            public LeaderboardEntry[] entries;
        }

        // ==============================================
        // Stats API
        // ==============================================
        public IEnumerator GetUserStats(
            string userId,
            Action<UserStats> onSuccess,
            Action<string> onError = null)
        {
            string url = $"{baseUrl}/stats/{userId}";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                AddAuthHeader(request);
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    var stats = JsonUtility.FromJson<UserStats>(request.downloadHandler.text);
                    onSuccess?.Invoke(stats);
                }
                else
                {
                    Debug.LogWarning($"Stats API error: {request.error}");
                    onError?.Invoke(request.error);
                }
            }
        }

        [Serializable]
        public class UserStats
        {
            public string user_id;
            public int overall_level;
            public float math_level;
            public float german_level;
            public float english_level;
            public int total_play_time_minutes;
            public int total_sessions;
            public int questions_answered;
            public int questions_correct;
            public float accuracy;
        }

        // ==============================================
        // Health Check
        // ==============================================
        public IEnumerator HealthCheck(Action<bool, string> onComplete)
        {
            string url = $"{baseUrl}/health";

            using (UnityWebRequest request = UnityWebRequest.Get(url))
            {
                request.timeout = 5;
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    onComplete?.Invoke(true, request.downloadHandler.text);
                }
                else
                {
                    onComplete?.Invoke(false, request.error);
                }
            }
        }
    }
}
