using System;
using System.Collections.Generic;
using AIImages.Settings;

namespace AIImages.Validation
{
    /// <summary>
    /// Валидатор для настроек мода AI Images
    /// </summary>
    public static class SettingsValidator
    {
        /// <summary>
        /// Валидирует все настройки и возвращает список ошибок
        /// </summary>
        public static ValidationResult Validate(AIImagesModSettings settings)
        {
            var result = new ValidationResult();

            if (settings == null)
            {
                result.AddError("Settings object is null");
                return result;
            }

            // Валидация API endpoint
            ValidateApiEndpoint(settings.apiEndpoint, result);

            // Валидация размеров изображения
            ValidateImageDimensions(settings.width, settings.height, result);

            // Валидация steps
            ValidateSteps(settings.steps, result);

            // Валидация CFG scale
            ValidateCfgScale(settings.cfgScale, result);

            // Валидация sampler и scheduler
            ValidateSamplerAndScheduler(
                settings.selectedSampler,
                settings.selectedScheduler,
                result
            );

            // Валидация пути сохранения
            ValidateSavePath(settings.savePath, result);

            return result;
        }

        private static void ValidateApiEndpoint(string endpoint, ValidationResult result)
        {
            if (string.IsNullOrWhiteSpace(endpoint))
            {
                result.AddError("API endpoint cannot be empty");
                return;
            }

            if (!Uri.TryCreate(endpoint, UriKind.Absolute, out Uri uri))
            {
                result.AddError($"Invalid API endpoint format: {endpoint}");
                return;
            }

            if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
            {
                result.AddWarning($"API endpoint should use HTTP or HTTPS protocol: {endpoint}");
            }

            // Проверка на localhost/127.0.0.1
            if (
                uri.Host != "localhost"
                && uri.Host != "127.0.0.1"
                && !uri.Host.StartsWith("192.168.")
            )
            {
                result.AddWarning(
                    "API endpoint is not pointing to a local address. Make sure the API is accessible."
                );
            }
        }

        private static void ValidateImageDimensions(int width, int height, ValidationResult result)
        {
            const int minDimension = 64;
            const int maxDimension = 2048;
            const int recommendedMin = 512;
            const int recommendedMax = 1024;

            if (width < minDimension || width > maxDimension)
            {
                result.AddError(
                    $"Width must be between {minDimension} and {maxDimension}. Current: {width}"
                );
            }

            if (height < minDimension || height > maxDimension)
            {
                result.AddError(
                    $"Height must be between {minDimension} and {maxDimension}. Current: {height}"
                );
            }

            // Проверка кратности 8 (рекомендация для Stable Diffusion)
            if (width % 8 != 0)
            {
                result.AddWarning(
                    $"Width should be divisible by 8 for optimal results. Current: {width}"
                );
            }

            if (height % 8 != 0)
            {
                result.AddWarning(
                    $"Height should be divisible by 8 for optimal results. Current: {height}"
                );
            }

            // Предупреждения о производительности
            if (width > recommendedMax || height > recommendedMax)
            {
                result.AddWarning(
                    $"Large image dimensions ({width}x{height}) may result in slow generation and high memory usage"
                );
            }

            if (width < recommendedMin || height < recommendedMin)
            {
                result.AddWarning(
                    $"Small image dimensions ({width}x{height}) may result in lower quality"
                );
            }
        }

        private static void ValidateSteps(int steps, ValidationResult result)
        {
            const int minSteps = 1;
            const int maxSteps = 150;
            const int recommendedMin = 20;
            const int recommendedMax = 50;

            if (steps < minSteps || steps > maxSteps)
            {
                result.AddError(
                    $"Steps must be between {minSteps} and {maxSteps}. Current: {steps}"
                );
            }

            if (steps < recommendedMin)
            {
                result.AddWarning(
                    $"Low steps value ({steps}) may result in lower quality. Recommended: {recommendedMin}-{recommendedMax}"
                );
            }

            if (steps > recommendedMax)
            {
                result.AddWarning(
                    $"High steps value ({steps}) may result in slow generation with minimal quality improvement"
                );
            }
        }

        private static void ValidateCfgScale(float cfgScale, ValidationResult result)
        {
            const float minCfg = 1.0f;
            const float maxCfg = 30.0f;
            const float recommendedMin = 5.0f;
            const float recommendedMax = 15.0f;

            if (cfgScale < minCfg || cfgScale > maxCfg)
            {
                result.AddError(
                    $"CFG Scale must be between {minCfg} and {maxCfg}. Current: {cfgScale}"
                );
            }

            if (cfgScale < recommendedMin)
            {
                result.AddWarning(
                    $"Low CFG scale ({cfgScale}) may ignore prompt. Recommended: {recommendedMin}-{recommendedMax}"
                );
            }

            if (cfgScale > recommendedMax)
            {
                result.AddWarning(
                    $"High CFG scale ({cfgScale}) may result in over-saturated or distorted images"
                );
            }
        }

        private static void ValidateSamplerAndScheduler(
            string sampler,
            string scheduler,
            ValidationResult result
        )
        {
            if (string.IsNullOrWhiteSpace(sampler))
            {
                result.AddWarning("Sampler is not selected. A default sampler will be used.");
            }

            if (string.IsNullOrWhiteSpace(scheduler))
            {
                result.AddWarning("Scheduler is not selected. A default scheduler will be used.");
            }
        }

        private static void ValidateSavePath(string savePath, ValidationResult result)
        {
            if (string.IsNullOrWhiteSpace(savePath))
            {
                result.AddError("Save path cannot be empty");
                return;
            }

            // Проверка на недопустимые символы в пути
            char[] invalidChars = System.IO.Path.GetInvalidPathChars();
            if (savePath.IndexOfAny(invalidChars) >= 0)
            {
                result.AddError($"Save path contains invalid characters: {savePath}");
            }
        }
    }

    /// <summary>
    /// Результат валидации настроек
    /// </summary>
    public class ValidationResult
    {
        private readonly List<string> _errors = new List<string>();
        private readonly List<string> _warnings = new List<string>();

        public bool IsValid => _errors.Count == 0;
        public bool HasWarnings => _warnings.Count > 0;
        public IReadOnlyList<string> Errors => _errors;
        public IReadOnlyList<string> Warnings => _warnings;

        public void AddError(string error)
        {
            if (!string.IsNullOrWhiteSpace(error))
            {
                _errors.Add(error);
            }
        }

        public void AddWarning(string warning)
        {
            if (!string.IsNullOrWhiteSpace(warning))
            {
                _warnings.Add(warning);
            }
        }

        public string GetErrorsAsString()
        {
            return string.Join("\n", _errors);
        }

        public string GetWarningsAsString()
        {
            return string.Join("\n", _warnings);
        }

        public string GetAllMessagesAsString()
        {
            var messages = new List<string>();

            if (_errors.Count > 0)
            {
                messages.Add("Errors:");
                messages.AddRange(_errors);
            }

            if (_warnings.Count > 0)
            {
                if (messages.Count > 0)
                    messages.Add("");

                messages.Add("Warnings:");
                messages.AddRange(_warnings);
            }

            return string.Join("\n", messages);
        }
    }
}
