using System;
using System.Linq;
using System.Threading;
using AIImages.Helpers;
using AIImages.Models;
using AIImages.Services;
using RimWorld;
using UnityEngine;
using Verse;

#pragma warning disable IDE1006 // Naming Styles

namespace AIImages
{
    /// <summary>
    /// Окно для просмотра персонажа и генерации AI изображений
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage(
        "Style",
        "IDE1006:Naming Styles",
        Justification = "RimWorld Window naming convention"
    )]
    [System.Diagnostics.CodeAnalysis.SuppressMessage(
        "Minor Code Smell",
        "S101:Types should be named in PascalCase",
        Justification = "RimWorld Window naming convention"
    )]
    public class Window_AIImage : Window
    {
        private Pawn pawn;
        private PawnAppearanceData appearanceData;
        private StableDiffusionSettings generationSettings;

        private Texture2D generatedImage;
        private bool isGenerating = false;
        private string generationStatus = "";
        private CancellationTokenSource cancellationTokenSource;

        // Прогресс генерации
        private double generationProgress = 0.0;
        private int currentStep = 0;
        private int totalSteps = 0;
        private double etaSeconds = 0.0;

        // Сервисы (получаем через DI)
        private readonly IPawnDescriptionService pawnDescriptionService;
        private readonly IPromptGeneratorService promptGeneratorService;
        private readonly IStableDiffusionApiService apiService;

        public Window_AIImage(Pawn pawn)
        {
            this.pawn = pawn;
            this.doCloseX = true;
            this.doCloseButton = true;
            this.forcePause = false;
            this.absorbInputAroundWindow = false;
            this.draggable = true;
            this.preventCameraMotion = false;

            // Получаем сервисы через DI контейнер
            var services = AIImagesMod.Services;
            pawnDescriptionService = services.PawnDescriptionService;
            promptGeneratorService = services.PromptGeneratorService;
            apiService = services.ApiService;

            // Извлекаем данные персонажа
            RefreshPawnData();
        }

        public override Vector2 InitialSize => new Vector2(900f, 800f);

        private Vector2 scrollPosition = Vector2.zero;
        private Vector2 promptScrollPosition = Vector2.zero;
        private Vector2 negativePromptScrollPosition = Vector2.zero;
        private float copiedMessageTime = 0f;

        /// <summary>
        /// Обновляет данные персонажа
        /// </summary>
        private void RefreshPawnData()
        {
            appearanceData = pawnDescriptionService.ExtractAppearanceData(pawn);
            generationSettings = AIImagesMod.Settings.ToStableDiffusionSettings();

            // Загружаем сохраненный портрет, если есть
            LoadSavedPortrait();
        }

        /// <summary>
        /// Загружает сохраненный портрет персонажа
        /// </summary>
        private void LoadSavedPortrait()
        {
            if (PawnPortraitHelper.HasPortrait(pawn))
            {
                generatedImage = PawnPortraitHelper.LoadPortrait(pawn);
                if (generatedImage != null)
                {
                    generationStatus = "AIImages.Generation.LoadedFromSave".Translate();
                }
            }
        }

        /// <summary>
        /// Освобождает ресурсы при закрытии окна
        /// </summary>
        public override void PreClose()
        {
            base.PreClose();

            // Отменяем генерацию, если она идет
            if (isGenerating && cancellationTokenSource != null)
            {
                cancellationTokenSource.Cancel();
            }

            // Освобождаем CancellationTokenSource
            cancellationTokenSource?.Dispose();
        }

        /// <summary>
        /// Обновляет текущую пешку в окне
        /// </summary>
        public void UpdatePawn(Pawn newPawn)
        {
            this.pawn = newPawn;
            RefreshPawnData();

            // Очищаем старое изображение при смене персонажа
            generatedImage = null;
            generationStatus = "";
            generationProgress = 0.0;
        }

        /// <summary>
        /// Получить текущую пешку
        /// </summary>
        public Pawn CurrentPawn => pawn;

        /// <summary>
        /// Вызывается каждый кадр для обновления окна
        /// </summary>
        public override void WindowUpdate()
        {
            base.WindowUpdate();

            // Проверяем, изменилась ли выбранная пешка
            Pawn selectedPawn = Find.Selector.SelectedPawns.FirstOrDefault(p =>
                p.IsColonist && p.Spawned && p.Faction == Faction.OfPlayer
            );

            // Если выбрана новая колонистская пешка, обновляем окно
            if (selectedPawn != null && selectedPawn != pawn)
            {
                UpdatePawn(selectedPawn);
            }

            // Уменьшаем таймер сообщения о копировании
            if (copiedMessageTime > 0f)
            {
                copiedMessageTime -= Time.deltaTime;
            }
        }

        /// <summary>
        /// Асинхронная генерация изображения с поддержкой отмены
        /// </summary>
        private async System.Threading.Tasks.Task GenerateImageAsync()
        {
            if (isGenerating)
                return;

            // Создаем новый CancellationTokenSource
            cancellationTokenSource?.Dispose();
            cancellationTokenSource = new CancellationTokenSource();

            isGenerating = true;
            generationStatus = "AIImages.Generation.InProgress".Translate();
            generationProgress = 0.0;
            currentStep = 0;
            totalSteps = generationSettings.Steps;

            try
            {
                // Генерируем промпты
                string positivePrompt = promptGeneratorService.GeneratePositivePrompt(
                    appearanceData,
                    generationSettings
                );
                string negativePrompt = promptGeneratorService.GenerateNegativePrompt(
                    generationSettings
                );

                // Создаем запрос
                var request = new GenerationRequest
                {
                    Prompt = positivePrompt,
                    NegativePrompt = negativePrompt,
                    Steps = generationSettings.Steps,
                    CfgScale = generationSettings.CfgScale,
                    Width = generationSettings.Width,
                    Height = generationSettings.Height,
                    Sampler = generationSettings.Sampler,
                    Scheduler = generationSettings.Scheduler,
                    Seed = generationSettings.Seed,
                    Model = AIImagesMod.Settings.apiEndpoint,
                    SaveImagesToServer = AIImagesMod.Settings.saveImagesToServer,
                };

                // Создаем отдельный CancellationTokenSource для мониторинга прогресса
                var progressCts = new CancellationTokenSource();
                var progressTask = MonitorProgressAsync(progressCts.Token);

                // Генерируем изображение с поддержкой отмены
                var result = await apiService.GenerateImageAsync(
                    request,
                    cancellationTokenSource.Token
                );

                // Останавливаем мониторинг прогресса
                progressCts.Cancel();
                try
                {
                    await progressTask;
                }
                catch (OperationCanceledException)
                {
                    // Ожидаемое исключение при остановке мониторинга
                }
                finally
                {
                    progressCts.Dispose();
                }

                if (result.Success)
                {
                    // Загружаем текстуру
                    generatedImage = new Texture2D(2, 2);
                    generatedImage.LoadImage(result.ImageData);
                    generationStatus = "AIImages.Generation.Success".Translate();
                    generationProgress = 1.0;

                    // Сохраняем путь к портрету на персонаже
                    PawnPortraitHelper.SavePortraitPath(pawn, result.SavedPath);

                    Messages.Message(
                        "AIImages.Generation.SavedTo".Translate(result.SavedPath),
                        MessageTypeDefOf.PositiveEvent
                    );
                }
                else
                {
                    generationStatus =
                        $"AIImages.Generation.Failed".Translate() + ": {result.ErrorMessage}";
                    Messages.Message(generationStatus, MessageTypeDefOf.RejectInput);
                }
            }
            catch (OperationCanceledException)
            {
                generationStatus = "AIImages.Generation.Cancelled".Translate();
                Log.Message("[AI Images] Generation cancelled by user");
            }
            catch (Exception ex)
            {
                generationStatus = $"Error: {ex.Message}";
                Log.Error($"[AI Images] Generation error: {ex}");
                Messages.Message(
                    $"AIImages.Generation.Error".Translate() + ": {ex.Message}",
                    MessageTypeDefOf.RejectInput
                );
            }
            finally
            {
                isGenerating = false;
            }
        }

        /// <summary>
        /// Мониторит прогресс генерации и обновляет UI
        /// </summary>
        private async System.Threading.Tasks.Task MonitorProgressAsync(
            CancellationToken cancellationToken
        )
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var progress = await apiService.GetProgressAsync(cancellationToken);

                    if (progress != null && progress.IsActive)
                    {
                        generationProgress = progress.Progress;
                        currentStep = progress.CurrentStep;
                        totalSteps = progress.TotalSteps;
                        etaSeconds = progress.EtaRelative;

                        Log.Message(
                            $"[AI Images] Progress: {progress.Progress:P} - Step {progress.CurrentStep}/{progress.TotalSteps} - ETA: {progress.EtaRelative:F1}s"
                        );
                    }

                    // Обновляем каждые 500ms
                    await System.Threading.Tasks.Task.Delay(500, cancellationToken);
                }
            }
            catch (OperationCanceledException)
            {
                // Ожидаемое исключение при остановке
            }
            catch (Exception ex)
            {
                Log.Warning($"[AI Images] Progress monitoring error: {ex.Message}");
            }
        }

        /// <summary>
        /// Запускает генерацию изображения (обертка для безопасного fire-and-forget)
        /// </summary>
        private void StartGeneration()
        {
            AsyncHelper.FireAndForget(GenerateImageAsync(), "Image Generation");
        }

        /// <summary>
        /// Отменяет генерацию изображения
        /// </summary>
        private void CancelGeneration()
        {
            if (isGenerating && cancellationTokenSource != null)
            {
                cancellationTokenSource.Cancel();
                generationStatus = "AIImages.Generation.Cancelling".Translate();
            }
        }

        public override void DoWindowContents(Rect inRect)
        {
            float curY = 0f;

            // Заголовок
            Text.Font = GameFont.Medium;
            Widgets.Label(
                new Rect(0f, curY, inRect.width, 40f),
                "AIImages.Window.Title".Translate()
            );
            curY += 45f;

            // Имя пешки
            Text.Font = GameFont.Small;
            Widgets.Label(
                new Rect(0f, curY, inRect.width, 30f),
                "AIImages.Window.PawnLabel".Translate(pawn.NameShortColored.Resolve())
            );
            curY += 40f;

            // Разделитель
            Widgets.DrawLineHorizontal(0f, curY, inRect.width);
            curY += 10f;

            // Разделяем на две колонки: левая - информация, правая - изображение
            float leftColumnWidth = inRect.width * 0.55f;
            float rightColumnWidth = inRect.width * 0.42f;
            float columnGap = inRect.width * 0.03f;

            // Левая колонка - прокручиваемая информация
            Rect leftColumnRect = new Rect(0f, curY, leftColumnWidth, inRect.height - curY);
            DrawLeftColumn(leftColumnRect);

            // Правая колонка - превью и управление
            Rect rightColumnRect = new Rect(
                leftColumnWidth + columnGap,
                curY,
                rightColumnWidth,
                inRect.height - curY
            );
            DrawRightColumn(rightColumnRect);
        }

        private void DrawLeftColumn(Rect rect)
        {
            Rect scrollViewRect = new Rect(0f, 0f, rect.width - 20f, CalculateContentHeight());
            Widgets.BeginScrollView(rect, ref scrollPosition, scrollViewRect);

            float contentY = 0f;

            // Портрет персонажа (если есть)
            if (generatedImage != null)
            {
                float portraitSize = Mathf.Min(scrollViewRect.width - 20f, 200f);
                Rect portraitRect = new Rect(
                    (scrollViewRect.width - portraitSize) / 2f,
                    contentY,
                    portraitSize,
                    portraitSize
                );
                GUI.DrawTexture(portraitRect, generatedImage);
                contentY += portraitSize + 15f;
            }

            // Секция "Внешность"
            Text.Font = GameFont.Medium;
            Widgets.Label(
                new Rect(10f, contentY, scrollViewRect.width - 20f, 30f),
                "AIImages.Appearance.SectionTitle".Translate()
            );
            contentY += 35f;

            Text.Font = GameFont.Small;
            string appearanceText = pawnDescriptionService.GetAppearanceDescription(pawn);
            float appearanceHeight = Text.CalcHeight(appearanceText, scrollViewRect.width - 30f);
            Widgets.Label(
                new Rect(20f, contentY, scrollViewRect.width - 30f, appearanceHeight),
                appearanceText
            );
            contentY += appearanceHeight + 20f;

            // Разделитель
            Widgets.DrawLineHorizontal(10f, contentY, scrollViewRect.width - 20f);
            contentY += 15f;

            // Секция "Одежда"
            Text.Font = GameFont.Medium;
            Widgets.Label(
                new Rect(10f, contentY, scrollViewRect.width - 20f, 30f),
                "AIImages.Apparel.SectionTitle".Translate()
            );
            contentY += 35f;

            Text.Font = GameFont.Small;
            string apparelText = pawnDescriptionService.GetApparelDescription(pawn);
            float apparelHeight = Text.CalcHeight(apparelText, scrollViewRect.width - 30f);
            Widgets.Label(
                new Rect(20f, contentY, scrollViewRect.width - 30f, apparelHeight),
                apparelText
            );

            Widgets.EndScrollView();
        }

        private void DrawRightColumn(Rect rect)
        {
            float curY = 0f;

            curY = DrawImagePreview(rect, curY);
            curY = DrawGenerationStatus(rect, curY);
            curY = DrawProgressBar(rect, curY);
            curY = DrawGenerationButton(rect, curY);

            // Позитивный промпт секция
            Text.Font = GameFont.Medium;
            Widgets.Label(
                new Rect(rect.x, rect.y + curY, rect.width, 30f),
                "AIImages.Prompt.PositiveTitle".Translate()
            );
            curY += 35f;

            // Получаем позитивный промпт
            Text.Font = GameFont.Tiny;
            string positivePrompt = promptGeneratorService.GeneratePositivePrompt(
                appearanceData,
                generationSettings
            );

            // Фиксированная высота для области промпта
            float promptBoxHeight = 100f;
            float actualPositiveHeight = Text.CalcHeight(positivePrompt, rect.width - 20f);

            Rect positiveOuterRect = new Rect(rect.x, rect.y + curY, rect.width, promptBoxHeight);
            Rect positiveViewRect = new Rect(0f, 0f, rect.width - 20f, actualPositiveHeight);

            // Рисуем фон
            Widgets.DrawBoxSolid(positiveOuterRect, new Color(0.1f, 0.3f, 0.1f, 0.5f));

            // Рисуем промпт с прокруткой
            Widgets.BeginScrollView(
                positiveOuterRect.ContractedBy(5f),
                ref promptScrollPosition,
                positiveViewRect
            );
            Widgets.Label(
                new Rect(0f, 0f, positiveViewRect.width, positiveViewRect.height),
                positivePrompt
            );
            Widgets.EndScrollView();

            curY += promptBoxHeight + 10f;

            // Негативный промпт секция
            Text.Font = GameFont.Medium;
            Widgets.Label(
                new Rect(rect.x, rect.y + curY, rect.width, 30f),
                "AIImages.Prompt.NegativeTitle".Translate()
            );
            curY += 35f;

            // Получаем негативный промпт
            Text.Font = GameFont.Tiny;
            string negativePrompt = promptGeneratorService.GenerateNegativePrompt(
                generationSettings
            );

            float actualNegativeHeight = Text.CalcHeight(negativePrompt, rect.width - 20f);

            Rect negativeOuterRect = new Rect(rect.x, rect.y + curY, rect.width, promptBoxHeight);
            Rect negativeViewRect = new Rect(0f, 0f, rect.width - 20f, actualNegativeHeight);

            // Рисуем фон (красноватый для негативного)
            Widgets.DrawBoxSolid(negativeOuterRect, new Color(0.3f, 0.1f, 0.1f, 0.5f));

            // Рисуем промпт с прокруткой
            Widgets.BeginScrollView(
                negativeOuterRect.ContractedBy(5f),
                ref negativePromptScrollPosition,
                negativeViewRect
            );
            Widgets.Label(
                new Rect(0f, 0f, negativeViewRect.width, negativeViewRect.height),
                negativePrompt
            );
            Widgets.EndScrollView();

            curY += promptBoxHeight + 10f;

            // Кнопки копирования промптов
            if (
                Widgets.ButtonText(
                    new Rect(rect.x, rect.y + curY, rect.width / 2f - 5f, 30f),
                    "AIImages.Prompt.CopyPositive".Translate()
                )
            )
            {
                string positiveForCopy = promptGeneratorService.GeneratePositivePrompt(
                    appearanceData,
                    generationSettings
                );
                GUIUtility.systemCopyBuffer = positiveForCopy;
                copiedMessageTime = 2f;
            }

            if (
                Widgets.ButtonText(
                    new Rect(
                        rect.x + rect.width / 2f + 5f,
                        rect.y + curY,
                        rect.width / 2f - 5f,
                        30f
                    ),
                    "AIImages.Prompt.CopyNegative".Translate()
                )
            )
            {
                string negativeForCopy = promptGeneratorService.GenerateNegativePrompt(
                    generationSettings
                );
                GUIUtility.systemCopyBuffer = negativeForCopy;
                copiedMessageTime = 2f;
            }
            curY += 35f;

            // Кнопка обновления данных
            if (
                Widgets.ButtonText(
                    new Rect(rect.x, rect.y + curY, rect.width, 30f),
                    "AIImages.Window.Refresh".Translate()
                )
            )
            {
                RefreshPawnData();
            }

            // Сообщение о копировании
            if (copiedMessageTime > 0f)
            {
                curY += 35f;
                GUI.color = new Color(0f, 1f, 0f, copiedMessageTime / 2f);
                Widgets.Label(
                    new Rect(rect.x, rect.y + curY, rect.width, 25f),
                    "AIImages.Prompt.Copied".Translate()
                );
                GUI.color = Color.white;
            }
        }

        private float CalculateContentHeight()
        {
            float height = 0f;

            // Портрет персонажа (если есть)
            if (generatedImage != null)
            {
                float portraitSize = Mathf.Min(400f, 200f);
                height += portraitSize + 15f;
            }

            // Заголовок "Внешность"
            height += 35f;

            // Текст внешности
            string appearanceText = pawnDescriptionService.GetAppearanceDescription(pawn);
            height += Text.CalcHeight(appearanceText, 400f) + 20f;

            // Разделитель
            height += 15f;

            // Заголовок "Одежда"
            height += 35f;

            // Текст одежды
            string apparelText = pawnDescriptionService.GetApparelDescription(pawn);
            height += Text.CalcHeight(apparelText, 400f) + 20f;

            // Дополнительный отступ
            height += 50f;

            // Позитивный промпт заголовок
            height += 35f;
            // Позитивный промпт контент
            height += 100f + 10f;

            // Негативный промпт заголовок
            height += 35f;
            // Негативный промпт контент
            height += 100f + 10f;

            // Кнопки копирования
            height += 35f;

            // Кнопка обновления
            height += 35f;

            // Сообщение о копировании
            if (copiedMessageTime > 0f)
            {
                height += 30f;
            }

            return height;
        }

        private float DrawImagePreview(Rect rect, float curY)
        {
            if (generatedImage != null)
            {
                float imageSize = Mathf.Min(rect.width, 400f);
                Rect imageRect = new Rect(
                    rect.x + (rect.width - imageSize) / 2f,
                    rect.y + curY,
                    imageSize,
                    imageSize
                );
                GUI.DrawTexture(imageRect, generatedImage);
                return curY + imageSize + 10f;
            }

            float placeholderSize = Mathf.Min(rect.width, 300f);
            Rect placeholderRect = new Rect(
                rect.x + (rect.width - placeholderSize) / 2f,
                rect.y + curY,
                placeholderSize,
                placeholderSize
            );
            Widgets.DrawBoxSolid(placeholderRect, new Color(0.2f, 0.2f, 0.2f));
            Text.Anchor = TextAnchor.MiddleCenter;
            Widgets.Label(placeholderRect, "AIImages.Generation.NoImage".Translate());
            Text.Anchor = TextAnchor.UpperLeft;
            return curY + placeholderSize + 10f;
        }

        private float DrawGenerationStatus(Rect rect, float curY)
        {
            if (string.IsNullOrEmpty(generationStatus))
                return curY;

            Text.Font = GameFont.Small;
            float statusHeight = Text.CalcHeight(generationStatus, rect.width);
            Widgets.Label(
                new Rect(rect.x, rect.y + curY, rect.width, statusHeight),
                generationStatus
            );
            return curY + statusHeight + 10f;
        }

        private float DrawProgressBar(Rect rect, float curY)
        {
            if (!isGenerating || generationProgress <= 0.0)
                return curY;

            Rect progressBarRect = new Rect(rect.x, rect.y + curY, rect.width, 24f);

            string progressText;
            if (totalSteps > 0)
            {
                progressText =
                    $"{(generationProgress * 100):F1}% - Step {currentStep}/{totalSteps}";
                if (etaSeconds > 0)
                {
                    progressText += $" - ETA: {etaSeconds:F0}s";
                }
            }
            else
            {
                progressText = $"{(generationProgress * 100):F1}%";
            }

            Widgets.FillableBar(progressBarRect, (float)generationProgress);
            Text.Font = GameFont.Tiny;
            Text.Anchor = TextAnchor.MiddleCenter;
            Widgets.Label(progressBarRect, progressText);
            Text.Anchor = TextAnchor.UpperLeft;
            return curY + 30f;
        }

        private float DrawGenerationButton(Rect rect, float curY)
        {
            Text.Font = GameFont.Small;
            string buttonLabel = isGenerating
                ? "AIImages.Generation.Cancel".Translate()
                : "AIImages.Generation.Generate".Translate();

            if (Widgets.ButtonText(new Rect(rect.x, rect.y + curY, rect.width, 35f), buttonLabel))
            {
                if (isGenerating)
                    CancelGeneration();
                else
                    StartGeneration();
            }
            return curY + 40f;
        }
    }
}
