using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using AIImages.Models;
using StableDiffusionNet;
using StableDiffusionNet.Exceptions;
using StableDiffusionNet.Interfaces;
using StableDiffusionNet.Models.Requests;
using Verse;

namespace AIImages.Services
{
    /// <summary>
    /// Адаптер для Stable Diffusion API (AUTOMATIC1111 WebUI)
    /// Использует библиотеку StableDiffusionNet для работы с API
    /// </summary>
    public class StableDiffusionNetAdapter : IStableDiffusionApiService, IDisposable
    {
        private readonly IStableDiffusionClient _client;
        private readonly string _saveFolderPath;
        private bool _disposed;

        public StableDiffusionNetAdapter(string apiEndpoint, string savePath = "AIImages/Generated")
        {
            if (string.IsNullOrEmpty(apiEndpoint))
            {
                throw new ArgumentException(
                    "API endpoint cannot be null or empty",
                    nameof(apiEndpoint)
                );
            }

            // Определяем путь для сохранения
            _saveFolderPath = Path.Combine(GenFilePaths.SaveDataFolderPath, savePath);

            // Создаем папку, если не существует
            if (!Directory.Exists(_saveFolderPath))
            {
                Directory.CreateDirectory(_saveFolderPath);
            }

            // Создаем клиент StableDiffusion используя Builder
            _client = new StableDiffusionClientBuilder()
                .WithBaseUrl(apiEndpoint)
                .WithTimeout(300) // 5 минут в секундах
                .WithRetry(retryCount: 3, retryDelayMilliseconds: 1000)
                .Build();

            Log.Message(
                $"[AI Images] StableDiffusion adapter initialized with endpoint: {apiEndpoint}"
            );
        }

        public async Task<GenerationResult> GenerateImageAsync(
            GenerationRequest request,
            CancellationToken cancellationToken = default
        )
        {
            ThrowIfDisposed();

            if (request == null)
            {
                return GenerationResult.Failure("Request cannot be null");
            }

            try
            {
                Log.Message(
                    $"[AI Images] Starting image generation with prompt: {request.Prompt.Substring(0, Math.Min(50, request.Prompt.Length))}..."
                );

                // Маппируем наш запрос на запрос библиотеки StableDiffusionNet
                var sdRequest = new TextToImageRequest
                {
                    Prompt = request.Prompt,
                    NegativePrompt = request.NegativePrompt,
                    Steps = request.Steps,
                    CfgScale = request.CfgScale,
                    Width = request.Width,
                    Height = request.Height,
                    SamplerName = request.Sampler,
                    Scheduler = request.Scheduler,
                    Seed = request.Seed,
                    SaveImages = request.SaveImagesToServer, // Сохранять ли изображения на сервере
                };

                // Выполняем запрос через библиотеку (с встроенной retry логикой)
                var response = await _client.TextToImage.GenerateAsync(
                    sdRequest,
                    cancellationToken
                );

                if (response?.Images == null || response.Images.Count == 0)
                {
                    return GenerationResult.Failure("No images returned from API");
                }

                // Декодируем изображение из base64
                byte[] imageData = Convert.FromBase64String(response.Images[0]);

                // Сохраняем изображение
                string fileName = $"pawn_{DateTime.Now:yyyyMMdd_HHmmss}.png";
                string fullPath = Path.Combine(_saveFolderPath, fileName);
                await File.WriteAllBytesAsync(fullPath, imageData);

                Log.Message($"[AI Images] Image generated successfully and saved to: {fullPath}");

                return GenerationResult.SuccessResult(imageData, fullPath, request);
            }
            catch (TaskCanceledException)
            {
                Log.Warning("[AI Images] Request timeout. Generation took too long.");
                return GenerationResult.Failure("Request timeout. Generation took too long.");
            }
            catch (OperationCanceledException)
            {
                Log.Message("[AI Images] Image generation was cancelled");
                return GenerationResult.Failure("Generation cancelled");
            }
            catch (HttpRequestException ex)
            {
                Log.Error($"[AI Images] HTTP error: {ex.Message}");
                return GenerationResult.Failure($"Connection error: {ex.Message}");
            }
            catch (StableDiffusionException ex)
            {
                Log.Error($"[AI Images] StableDiffusion API error: {ex.Message}");
                return GenerationResult.Failure($"API Error: {ex.Message}");
            }
            catch (Exception ex)
            {
                Log.Error($"[AI Images] Unexpected error: {ex.Message}\n{ex.StackTrace}");
                return GenerationResult.Failure($"Error: {ex.Message}");
            }
        }

        public async Task<GenerationProgress> GetProgressAsync(
            CancellationToken cancellationToken = default
        )
        {
            ThrowIfDisposed();

            try
            {
                // Используем Progress сервис библиотеки
                var progress = await _client.Progress.GetProgressAsync(cancellationToken);

                // Маппируем на наш тип
                return new GenerationProgress
                {
                    Progress = progress.Progress,
                    CurrentStep = progress.State?.SamplingStep ?? 0,
                    TotalSteps = progress.State?.SamplingSteps ?? 0,
                    EtaRelative = progress.EtaRelative,
                    IsActive = progress.Progress > 0 && progress.Progress < 1.0,
                    CurrentImage = progress.CurrentImage, // Превью текущего состояния генерации
                };
            }
            catch (Exception ex)
            {
                Log.Warning($"[AI Images] Failed to get progress: {ex.Message}");
                // Возвращаем пустой прогресс при ошибке
                return new GenerationProgress
                {
                    Progress = 0,
                    CurrentStep = 0,
                    TotalSteps = 0,
                    EtaRelative = 0,
                    IsActive = false,
                };
            }
        }

        public async Task<bool> CheckApiAvailability(
            string apiEndpoint,
            CancellationToken cancellationToken = default
        )
        {
            ThrowIfDisposed();

            try
            {
                // Используем встроенный метод HealthCheckAsync библиотеки
                var healthCheck = await _client.HealthCheckAsync(cancellationToken);
                return healthCheck.IsHealthy;
            }
            catch (Exception ex)
            {
                Log.Warning($"[AI Images] API check failed: {ex.Message}");
                return false;
            }
        }

        public async Task<List<string>> GetAvailableModels(
            string apiEndpoint,
            CancellationToken cancellationToken = default
        )
        {
            ThrowIfDisposed();

            try
            {
                // Используем Models сервис библиотеки
                var models = await _client.Models.GetModelsAsync(cancellationToken);

                var modelNames = new List<string>();
                if (models != null)
                {
                    foreach (var model in models)
                    {
                        // Используем Title или ModelName в зависимости от того, что доступно
                        modelNames.Add(model.Title ?? model.ModelName);
                    }
                }

                Log.Message($"[AI Images] Found {modelNames.Count} models");
                return modelNames;
            }
            catch (Exception ex)
            {
                Log.Error($"[AI Images] Failed to load models: {ex.Message}");
                return new List<string>();
            }
        }

        public async Task<List<string>> GetAvailableSamplers(
            string apiEndpoint,
            CancellationToken cancellationToken = default
        )
        {
            ThrowIfDisposed();

            try
            {
                // Используем Samplers сервис библиотеки
                var samplers = await _client.Samplers.GetSamplersAsync(cancellationToken);

                var samplerNames = new List<string>();
                if (samplers != null)
                {
                    foreach (var sampler in samplers)
                    {
                        samplerNames.Add(sampler.Name);
                    }
                }

                Log.Message($"[AI Images] Found {samplerNames.Count} samplers");
                return samplerNames;
            }
            catch (Exception ex)
            {
                Log.Warning($"[AI Images] Failed to load samplers: {ex.Message}");
                return GetDefaultSamplers();
            }
        }

        public async Task<List<string>> GetAvailableSchedulers(
            string apiEndpoint,
            CancellationToken cancellationToken = default
        )
        {
            ThrowIfDisposed();

            try
            {
                // Используем Schedulers сервис библиотеки (доступен с версии 1.1.1)
                var schedulers = await _client.Schedulers.GetSchedulersAsync(cancellationToken);

                var schedulerNames = new List<string>();
                if (schedulers != null)
                {
                    foreach (var scheduler in schedulers)
                    {
                        schedulerNames.Add(scheduler.Name);
                    }
                }

                Log.Message($"[AI Images] Found {schedulerNames.Count} schedulers");
                return schedulerNames;
            }
            catch (Exception ex)
            {
                Log.Warning($"[AI Images] Failed to load schedulers: {ex.Message}");
                return GetDefaultSchedulers();
            }
        }

        private List<string> GetDefaultSamplers()
        {
            return new List<string>
            {
                "Euler a",
                "Euler",
                "LMS",
                "Heun",
                "DPM2",
                "DPM2 a",
                "DPM++ 2S a",
                "DPM++ 2M",
                "DPM++ SDE",
                "DPM fast",
                "DPM adaptive",
                "LMS Karras",
                "DPM2 Karras",
                "DPM2 a Karras",
                "DPM++ 2S a Karras",
                "DPM++ 2M Karras",
                "DPM++ SDE Karras",
                "DDIM",
                "PLMS",
            };
        }

        private List<string> GetDefaultSchedulers()
        {
            return new List<string>
            {
                "Automatic",
                "Uniform",
                "Karras",
                "Exponential",
                "Polyexponential",
                "SGM Uniform",
            };
        }

        private void ThrowIfDisposed()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(StableDiffusionNetAdapter));
            }
        }

        public void Dispose()
        {
            if (_disposed)
                return;

            // Dispose клиента StableDiffusion
            if (_client is IDisposable disposableClient)
            {
                disposableClient.Dispose();
            }

            _disposed = true;
        }
    }
}
