﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using FrameDoctor.Editor.Config;

namespace FrameDoctor.Editor.Logic
{
    // Response from the upload API.
    [Serializable]
    public class UploadResponse
    {
        public string sessionId;
        public string status;
        public string error;
    }

    // Handles uploading profiler data to FrameDoctor API.
    // Only available in the direct-download version (FRAMEDOCTOR_CLOUD).
    public class UploadService
    {
        private const int MaxRetries = 3;
        private const int RetryDelayMs = 1000;

        public event Action<float> OnProgress;
        public event Action<string> OnComplete;
        public event Action<string> OnError;

        private bool _isCancelled;

        // Upload all CSV files from the export directory.
        // exportPath: Path to the session export directory
        // authToken: JWT authentication token
        // returns: Session ID on success, null on failure
        public async Task<string> UploadAsync(string exportPath, string authToken)
        {
            _isCancelled = false;

            if (string.IsNullOrEmpty(exportPath) || !Directory.Exists(exportPath))
            {
                OnError?.Invoke("Export path does not exist");
                return null;
            }

            var files = Directory.GetFiles(exportPath, "*.csv");
            if (files.Length == 0)
            {
                OnError?.Invoke("No CSV files found to upload");
                return null;
            }

            var summaryFile = Path.Combine(exportPath, "summary.txt");
            var allFiles = new List<string>(files);
            if (File.Exists(summaryFile))
            {
                allFiles.Add(summaryFile);
            }

            for (int attempt = 0; attempt < MaxRetries && !_isCancelled; attempt++)
            {
                try
                {
                    var result = await UploadFilesAsync(allFiles.ToArray(), authToken);
                    if (result != null)
                    {
                        OnComplete?.Invoke(result);
                        return result;
                    }
                }
                catch (Exception e)
                {
                    if (attempt < MaxRetries - 1)
                    {
                        FrameDoctorSettings.Log($"[FrameDoctor] Upload attempt {attempt + 1} failed, retrying...");
                        await Task.Delay(RetryDelayMs);
                    }
                    else
                    {
                        OnError?.Invoke($"Upload failed after {MaxRetries} attempts: {e.Message}");
                    }
                }
            }

            return null;
        }

        public void Cancel()
        {
            _isCancelled = true;
        }

        private async Task<string> UploadFilesAsync(string[] filePaths, string authToken)
        {
            var uploadUrl = $"{FrameDoctorConstants.ApiBaseUrl}{FrameDoctorConstants.UploadPath}";

            var formData = new List<IMultipartFormSection>();

            long totalSize = 0;
            foreach (var filePath in filePaths)
            {
                var fileInfo = new FileInfo(filePath);
                totalSize += fileInfo.Length;
            }

            long uploadedSize = 0;
            foreach (var filePath in filePaths)
            {
                if (_isCancelled) return null;

                var fileName = Path.GetFileName(filePath);
                var fileData = File.ReadAllBytes(filePath);
                var mimeType = fileName.EndsWith(".csv") ? "text/csv" : "text/plain";

                formData.Add(new MultipartFormFileSection("files", fileData, fileName, mimeType));

                uploadedSize += fileData.Length;
                OnProgress?.Invoke((float)uploadedSize / totalSize * 0.5f);
            }

            using (var request = UnityWebRequest.Post(uploadUrl, formData))
            {
                request.SetRequestHeader("Authorization", $"Bearer {authToken}");

                var operation = request.SendWebRequest();

                while (!operation.isDone && !_isCancelled)
                {
                    var progress = 0.5f + (operation.progress * 0.5f);
                    OnProgress?.Invoke(progress);
                    await Task.Delay(50);
                }

                if (_isCancelled)
                {
                    request.Abort();
                    return null;
                }

                OnProgress?.Invoke(1f);

                if (request.result == UnityWebRequest.Result.Success)
                {
                    var responseText = request.downloadHandler.text;
                    var response = JsonUtility.FromJson<UploadResponse>(responseText);

                    if (!string.IsNullOrEmpty(response.error))
                    {
                        OnError?.Invoke(response.error);
                        return null;
                    }

                    FrameDoctorSettings.Log($"[FrameDoctor] Upload complete - session: {response.sessionId}");
                    return response.sessionId;
                }
                else
                {
                    var errorMessage = $"HTTP {request.responseCode}: {request.error}";

                    if (request.responseCode == 401)
                    {
                        OnError?.Invoke("Authentication expired. Please log in again.");
                    }
                    else
                    {
                        OnError?.Invoke(errorMessage);
                    }

                    throw new Exception(errorMessage);
                }
            }
        }
    }
}
