using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.ComponentModel;
using System.Windows.Forms;
using AxCopilot.Models;
using AxCopilot.Services;
using AxCopilot.Themes;
using AxCopilot.Views;

namespace AxCopilot.ViewModels;

public partial class SettingsViewModel
{
    // ─── 인덱스 경로 메서드 ──────────────────────────────────────────────
    public void AddIndexPath(string path)
    {
        var trimmed = path.Trim();
        if (string.IsNullOrWhiteSpace(trimmed)) return;
        if (IndexPaths.Any(p => p.Equals(trimmed, StringComparison.OrdinalIgnoreCase))) return;
        IndexPaths.Add(trimmed);
    }

    public void RemoveIndexPath(string path) => IndexPaths.Remove(path);

    // ─── 인덱스 확장자 메서드 ──────────────────────────────────────────
    public void AddExtension(string ext)
    {
        var trimmed = ext.Trim().ToLowerInvariant();
        if (string.IsNullOrWhiteSpace(trimmed)) return;
        if (!trimmed.StartsWith(".")) trimmed = "." + trimmed;
        if (IndexExtensions.Any(e => e.Equals(trimmed, StringComparison.OrdinalIgnoreCase))) return;
        IndexExtensions.Add(trimmed);
    }

    public void RemoveExtension(string ext) => IndexExtensions.Remove(ext);

    public void BrowseIndexPath()
    {
        using var dlg = new FolderBrowserDialog
        {
            Description         = "인덱스할 폴더 선택",
            UseDescriptionForTitle = true,
            ShowNewFolderButton = false
        };
        if (dlg.ShowDialog() != DialogResult.OK) return;
        AddIndexPath(dlg.SelectedPath);
    }

    // ─── 빠른 실행 단축키 메서드 ──────────────────────────────────────────
    public bool AddShortcut()
    {
        if (string.IsNullOrWhiteSpace(_newKey) || string.IsNullOrWhiteSpace(_newTarget))
            return false;

        // 중복 키 확인
        if (AppShortcuts.Any(s => s.Key.Equals(_newKey.Trim(), StringComparison.OrdinalIgnoreCase)))
            return false;

        AppShortcuts.Add(new AppShortcutModel
        {
            Key         = _newKey.Trim(),
            Description = _newDescription.Trim(),
            Target      = _newTarget.Trim(),
            Type        = _newType
        });

        NewKey = ""; NewDescription = ""; NewTarget = ""; NewType = "app";
        return true;
    }

    public void RemoveShortcut(AppShortcutModel shortcut) => AppShortcuts.Remove(shortcut);

    /// <summary>파일 선택 대화상자. 선택 시 NewTarget에 자동 설정.</summary>
    public void BrowseTarget()
    {
        using var dlg = new OpenFileDialog
        {
            Filter = "실행 파일 (*.exe)|*.exe|모든 파일 (*.*)|*.*",
            Title  = "앱 선택"
        };
        if (dlg.ShowDialog() != DialogResult.OK) return;

        NewTarget = dlg.FileName;
        NewType   = "app";
        if (string.IsNullOrWhiteSpace(NewDescription))
            NewDescription = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName);
    }

    public void SelectTheme(string key)
    {
        SelectedThemeKey = key;
        ThemePreviewRequested?.Invoke(this, EventArgs.Empty);
    }

    public void PickColor(ColorRowModel row)
    {
        using var dlg = new ColorDialog { FullOpen = true };
        try
        {
            var color = ThemeResourceHelper.HexColor(row.Hex);
            dlg.Color = System.Drawing.Color.FromArgb(color.R, color.G, color.B);
        }
        catch (Exception) { /* 기본값 사용 */ }

        if (dlg.ShowDialog() != DialogResult.OK) return;

        row.Hex = $"#{dlg.Color.R:X2}{dlg.Color.G:X2}{dlg.Color.B:X2}";
        if (_selectedThemeKey == "custom")
            ThemePreviewRequested?.Invoke(this, EventArgs.Empty);
    }

    // 시스템 예약 프리픽스 (핸들러에서 이미 사용 중인 키)
    private static readonly HashSet<string> ReservedPrefixes = new(StringComparer.OrdinalIgnoreCase)
    {
        "=", "?", "#", "$", ";", "@", "~", ">", "!",
        "emoji", "color", "recent", "note", "uninstall", "kill", "media",
        "info", "*", "json", "encode", "port", "env", "snap", "help",
        "pick", "date", "svc", "pipe", "journal", "routine", "batch",
        "diff", "win", "stats", "fav", "rename", "monitor", "scaffold",
    };

    /// <summary>설정 저장 전 프리픽스/키워드 충돌을 검사합니다. 충돌 시 메시지를 반환합니다.</summary>
    public string? ValidateBeforeSave()
    {
        // 캡처 프리픽스 충돌 검사
        var cap = string.IsNullOrWhiteSpace(_capPrefix) ? "cap" : _capPrefix.Trim();
        if (cap != "cap" && ReservedPrefixes.Contains(cap))
            return $"캡처 프리픽스 '{cap}'은(는) 이미 사용 중인 예약어입니다.";

        // 빠른 실행 별칭 키 중복 검사
        var aliasKeys = AppShortcuts.Select(s => s.Key.ToLowerInvariant()).ToList();
        var duplicateAlias = aliasKeys.GroupBy(k => k).FirstOrDefault(g => g.Count() > 1);
        if (duplicateAlias != null)
            return $"빠른 실행 키워드 '{duplicateAlias.Key}'이(가) 중복되었습니다.";

        // 빠른 실행 별칭 키 vs 예약 프리픽스 충돌
        foreach (var key in aliasKeys)
        {
            if (ReservedPrefixes.Contains(key))
                return $"빠른 실행 키워드 '{key}'은(는) 시스템 예약어와 충돌합니다.";
        }

        // 배치 명령 키 중복 검사
        var batchKeys = BatchCommands.Select(b => b.Key.ToLowerInvariant()).ToList();
        var duplicateBatch = batchKeys.GroupBy(k => k).FirstOrDefault(g => g.Count() > 1);
        if (duplicateBatch != null)
            return $"배치 명령 키워드 '{duplicateBatch.Key}'이(가) 중복되었습니다.";

        return null; // 문제 없음
    }

    public void Save()
    {
        // 충돌 검사
        var conflict = ValidateBeforeSave();
        if (conflict != null)
        {
            CustomMessageBox.Show(
                conflict,
                "AX Copilot — 설정 저장 오류",
                System.Windows.MessageBoxButton.OK,
                System.Windows.MessageBoxImage.Warning);
            return;
        }

        var s = _service.Settings;
        s.Hotkey                     = _hotkey;
        s.Launcher.MaxResults        = _maxResults;
        s.Launcher.Opacity           = _opacity;
        s.Launcher.Theme             = _selectedThemeKey;
        s.Launcher.Position          = _launcherPosition;
        s.Launcher.WebSearchEngine   = _webSearchEngine;
        s.Launcher.SnippetAutoExpand = _snippetAutoExpand;
        s.Launcher.Language          = _language;
        L10n.SetLanguage(_language);

        // 기능 토글 저장
        s.Launcher.ShowNumberBadges = _showNumberBadges;
        s.Launcher.EnableFavorites  = _enableFavorites;
        s.Launcher.EnableRecent     = _enableRecent;
        s.Launcher.EnableActionMode = _enableActionMode;
        s.Launcher.CloseOnFocusLost = _closeOnFocusLost;
        s.Launcher.RememberPosition = _rememberPosition;
        s.Launcher.ShowPrefixBadge          = _showPrefixBadge;
        s.Launcher.EnableIconAnimation      = _enableIconAnimation;
        s.Launcher.EnableRainbowGlow        = _enableRainbowGlow;
        s.Launcher.EnableSelectionGlow      = _enableSelectionGlow;
        s.Launcher.EnableRandomPlaceholder  = _enableRandomPlaceholder;
        s.Launcher.ShowLauncherBorder       = _showLauncherBorder;
        s.Launcher.ShortcutHelpUseThemeColor = _shortcutHelpUseThemeColor;
        s.Launcher.EnableTextAction           = _enableTextAction;
        s.Launcher.EnableFileDialogIntegration = _enableFileDialogIntegration;
        s.Launcher.EnableClipboardAutoCategory = _enableClipboardAutoCategory;
        s.Launcher.MaxPinnedClipboardItems     = _maxPinnedClipboardItems;
        s.Launcher.TextActionTranslateLanguage = _textActionTranslateLanguage;
        s.Llm.MaxSubAgents       = _maxSubAgents;
        s.Llm.PdfExportPath      = _pdfExportPath;
        s.Llm.TipDurationSeconds = _tipDurationSeconds;

        // LLM 공통 설정 저장
        s.Llm.Service          = _llmService;
        s.Llm.Streaming        = _llmStreaming;
        s.Llm.MaxContextTokens = _llmMaxContextTokens;
        s.Llm.RetentionDays    = _llmRetentionDays;
        s.Llm.Temperature      = _llmTemperature;
        s.Llm.DefaultAgentPermission = _defaultAgentPermission;
        s.Llm.DefaultOutputFormat    = _defaultOutputFormat;
        s.Llm.DefaultMood            = _defaultMood;
        s.Llm.AutoPreview            = _autoPreview;
        s.Llm.MaxAgentIterations     = _maxAgentIterations;
        s.Llm.MaxRetryOnError        = _maxRetryOnError;
        s.Llm.AgentLogLevel          = _agentLogLevel;
        s.Llm.AgentDecisionLevel     = _agentDecisionLevel;
        s.Llm.PlanMode               = _planMode;
        s.Llm.EnableMultiPassDocument = _enableMultiPassDocument;
        s.Llm.EnableCoworkVerification = _enableCoworkVerification;
        s.Llm.EnableFilePathHighlight = _enableFilePathHighlight;
        s.Llm.FolderDataUsage        = _folderDataUsage;
        s.Llm.EnableAuditLog         = _enableAuditLog;
        s.Llm.EnableAgentMemory      = _enableAgentMemory;
        s.Llm.EnableProjectRules     = _enableProjectRules;
        s.Llm.MaxMemoryEntries       = _maxMemoryEntries;
        s.Llm.EnableImageInput       = _enableImageInput;
        s.Llm.MaxImageSizeKb         = _maxImageSizeKb;
        s.Llm.EnableToolHooks        = _enableToolHooks;
        s.Llm.ToolHookTimeoutMs      = _toolHookTimeoutMs;
        s.Llm.EnableSkillSystem      = _enableSkillSystem;
        s.Llm.SkillsFolderPath       = _skillsFolderPath;
        s.Llm.SlashPopupPageSize     = _slashPopupPageSize;
        s.Llm.EnableDragDropAiActions = _enableDragDropAiActions;
        s.Llm.DragDropAutoSend       = _dragDropAutoSend;
        s.Llm.Code.EnableCodeReview  = _enableCodeReview;
        s.Llm.EnableAutoRouter       = _enableAutoRouter;
        s.Llm.AutoRouterConfidence   = _autoRouterConfidence;
        s.Llm.EnableChatRainbowGlow  = _enableChatRainbowGlow;
        s.Llm.NotifyOnComplete       = _notifyOnComplete;
        s.Llm.ShowTips               = _showTips;
        s.Llm.DevMode                = _devMode;
        s.Llm.DevModeStepApproval    = _devModeStepApproval;
        s.Llm.WorkflowVisualizer     = _workflowVisualizer;
        s.Llm.FreeTierMode           = _freeTierMode;
        s.Llm.FreeTierDelaySeconds   = _freeTierDelaySeconds;
        s.Llm.ShowTotalCallStats     = _showTotalCallStats;

        // 서비스별 독립 설정 저장
        s.Llm.OllamaEndpoint = _ollamaEndpoint;
        s.Llm.OllamaModel   = _ollamaModel;
        s.Llm.VllmEndpoint   = _vllmEndpoint;
        s.Llm.VllmModel      = _vllmModel;
        s.Llm.GeminiModel    = _geminiModel;
        s.Llm.ClaudeModel    = _claudeModel;
        s.Llm.GeminiApiKey   = _geminiApiKey;
        s.Llm.ClaudeApiKey   = _claudeApiKey;

        // 내부 서비스 API 키 저장 (암호화 분기)
        if (!string.IsNullOrEmpty(_ollamaApiKey) && _ollamaApiKey != "(저장됨)")
            s.Llm.OllamaApiKey = CryptoService.EncryptIfEnabled(_ollamaApiKey, s.Llm.EncryptionEnabled);
        if (!string.IsNullOrEmpty(_vllmApiKey) && _vllmApiKey != "(저장됨)")
            s.Llm.VllmApiKey = CryptoService.EncryptIfEnabled(_vllmApiKey, s.Llm.EncryptionEnabled);

        // 활성 서비스의 설정을 기존 호환 필드에도 동기화 (LlmService.cs 호환)
        switch (_llmService)
        {
            case "ollama":
                s.Llm.Endpoint = _ollamaEndpoint;
                s.Llm.Model = _ollamaModel;
                s.Llm.EncryptedApiKey = s.Llm.OllamaApiKey;
                break;
            case "vllm":
                s.Llm.Endpoint = _vllmEndpoint;
                s.Llm.Model = _vllmModel;
                s.Llm.EncryptedApiKey = s.Llm.VllmApiKey;
                break;
            case "gemini":
                s.Llm.ApiKey = _geminiApiKey;
                s.Llm.Model = _geminiModel;
                break;
            case "claude":
                s.Llm.ApiKey = _claudeApiKey;
                s.Llm.Model = _claudeModel;
                break;
        }

        // 등록 모델 저장
        s.Llm.RegisteredModels = RegisteredModels
            .Where(rm => !string.IsNullOrWhiteSpace(rm.Alias))
            .Select(rm => new RegisteredModel
            {
                Alias = rm.Alias,
                EncryptedModelName = rm.EncryptedModelName,
                Service = rm.Service,
                Endpoint = rm.Endpoint,
                ApiKey = rm.ApiKey,
                AuthType = rm.AuthType ?? "bearer",
                Cp4dUrl = rm.Cp4dUrl ?? "",
                Cp4dUsername = rm.Cp4dUsername ?? "",
                Cp4dPassword = rm.Cp4dPassword ?? "",
            })
            .ToList();

        // 프롬프트 템플릿 저장
        s.Llm.PromptTemplates = PromptTemplates
            .Where(pt => !string.IsNullOrWhiteSpace(pt.Name))
            .Select(pt => new PromptTemplate { Name = pt.Name, Content = pt.Content, Icon = pt.Icon })
            .ToList();

        // 인덱스 경로 + 확장자 저장
        s.IndexPaths = IndexPaths.ToList();
        s.IndexExtensions = IndexExtensions.ToList();
        s.IndexSpeed = _indexSpeed;

        // 커스텀 색상 + 모양 저장
        var c = s.Launcher.CustomTheme ??= new CustomThemeColors();
        foreach (var row in ColorRows)
        {
            var prop = typeof(CustomThemeColors).GetProperty(row.Property);
            prop?.SetValue(c, row.Hex);
        }
        c.WindowCornerRadius = _customWindowCornerRadius;
        c.ItemCornerRadius   = _customItemCornerRadius;

        // 빠른 실행 단축키 저장:
        // batch/api/clipboard type은 그대로 유지, app/url/folder는 ViewModel 내용으로 교체
        var otherAliases = s.Aliases
            .Where(a => a.Type is not ("app" or "url" or "folder" or "batch"))
            .ToList();
        s.Aliases = otherAliases
            .Concat(AppShortcuts.Select(sc => new AliasEntry
            {
                Key         = sc.Key,
                Type        = sc.Type,
                Target      = sc.Target,
                Description = string.IsNullOrWhiteSpace(sc.Description) ? null : sc.Description
            }))
            .Concat(BatchCommands.Select(b => new AliasEntry
            {
                Key        = b.Key,
                Type       = "batch",
                Target     = b.Command,
                ShowWindow = b.ShowWindow
            }))
            .ToList();

        // 전용 핫키 저장
        s.CustomHotkeys = CustomHotkeys.Select(h => new Models.HotkeyAssignment
        {
            Hotkey = h.Hotkey,
            Target = h.Target,
            Label  = h.Label,
            Type   = h.Type
        }).ToList();

        // 스니펫 저장
        s.Snippets = Snippets.Select(sn => new SnippetEntry
        {
            Key     = sn.Key,
            Name    = sn.Name,
            Content = sn.Content
        }).ToList();

        // 알림 설정 저장
        s.Reminder.Enabled         = _reminderEnabled;
        s.Reminder.Corner          = _reminderCorner;
        s.Reminder.IntervalMinutes = _reminderIntervalMinutes;
        s.Reminder.DisplaySeconds  = _reminderDisplaySeconds;

        // 캡처 설정 저장
        s.ScreenCapture.Prefix              = string.IsNullOrWhiteSpace(_capPrefix) ? "cap" : _capPrefix.Trim();
        s.ScreenCapture.GlobalHotkeyEnabled = _capGlobalHotkeyEnabled;
        s.ScreenCapture.GlobalHotkey        = string.IsNullOrWhiteSpace(_capGlobalHotkey) ? "PrintScreen" : _capGlobalHotkey.Trim();
        s.ScreenCapture.GlobalHotkeyMode    = _capGlobalMode;
        s.ScreenCapture.ScrollDelayMs       = Math.Max(50, _capScrollDelayMs);

        // 클립보드 히스토리 설정 저장
        s.ClipboardHistory.Enabled  = _clipboardEnabled;
        s.ClipboardHistory.MaxItems = _clipboardMaxItems;

        // 시스템 명령 설정 저장
        var sc = s.SystemCommands;
        sc.ShowLock       = _sysShowLock;
        sc.ShowSleep      = _sysShowSleep;
        sc.ShowRestart    = _sysShowRestart;
        sc.ShowShutdown   = _sysShowShutdown;
        sc.ShowHibernate  = _sysShowHibernate;
        sc.ShowLogout     = _sysShowLogout;
        sc.ShowRecycleBin = _sysShowRecycleBin;

        // 시스템 명령 별칭 저장
        var cmdAliases = new Dictionary<string, List<string>>();
        void SaveAlias(string key, string val)
        {
            var list = ParseAliases(val);
            if (list.Count > 0) cmdAliases[key] = list;
        }
        SaveAlias("lock",      _aliasLock);
        SaveAlias("sleep",     _aliasSleep);
        SaveAlias("restart",   _aliasRestart);
        SaveAlias("shutdown",  _aliasShutdown);
        SaveAlias("hibernate", _aliasHibernate);
        SaveAlias("logout",    _aliasLogout);
        SaveAlias("recycle",   _aliasRecycle);
        sc.CommandAliases = cmdAliases;

        _service.Save();
        SaveCompleted?.Invoke(this, EventArgs.Empty);
    }

    public bool AddBatchCommand()
    {
        if (string.IsNullOrWhiteSpace(_newBatchKey) || string.IsNullOrWhiteSpace(_newBatchCommand))
            return false;
        if (BatchCommands.Any(b => b.Key.Equals(_newBatchKey.Trim(), StringComparison.OrdinalIgnoreCase)))
            return false;

        BatchCommands.Add(new BatchCommandModel
        {
            Key        = _newBatchKey.Trim(),
            Command    = _newBatchCommand.Trim(),
            ShowWindow = _newBatchShowWindow
        });
        NewBatchKey = ""; NewBatchCommand = ""; NewBatchShowWindow = false;
        return true;
    }

    public void RemoveBatchCommand(BatchCommandModel cmd) => BatchCommands.Remove(cmd);

    // ─── 전용 핫키 메서드 ─────────────────────────────────────────────────────

    public bool AddCustomHotkey()
    {
        if (string.IsNullOrWhiteSpace(_newHotkeyStr) || string.IsNullOrWhiteSpace(_newHotkeyTarget))
            return false;

        var hotkey = _newHotkeyStr.Trim();

        // 핫키 형식 검증
        if (!Core.HotkeyParser.TryParse(hotkey, out _))
        {
            CustomMessageBox.Show(
                $"핫키 형식이 올바르지 않습니다: '{hotkey}'\n예) Ctrl+Alt+1, Ctrl+Shift+F2",
                "AX Copilot — 핫키 오류",
                System.Windows.MessageBoxButton.OK,
                System.Windows.MessageBoxImage.Warning);
            return false;
        }

        // 중복 검사
        if (CustomHotkeys.Any(h => h.Hotkey.Equals(hotkey, StringComparison.OrdinalIgnoreCase)))
        {
            CustomMessageBox.Show(
                $"이미 등록된 핫키입니다: '{hotkey}'",
                "AX Copilot — 중복 핫키",
                System.Windows.MessageBoxButton.OK,
                System.Windows.MessageBoxImage.Warning);
            return false;
        }

        CustomHotkeys.Add(new HotkeyRowModel
        {
            Hotkey = hotkey,
            Target = _newHotkeyTarget.Trim(),
            Label  = string.IsNullOrWhiteSpace(_newHotkeyLabel) ? System.IO.Path.GetFileNameWithoutExtension(_newHotkeyTarget.Trim()) : _newHotkeyLabel.Trim(),
            Type   = _newHotkeyType
        });
        NewHotkeyStr = ""; NewHotkeyTarget = ""; NewHotkeyLabel = ""; NewHotkeyType = "app";
        return true;
    }

    public void RemoveCustomHotkey(HotkeyRowModel row) => CustomHotkeys.Remove(row);

    // ─── 스니펫 메서드 ──────────────────────────────────────────────────────
    public bool AddSnippet()
    {
        if (string.IsNullOrWhiteSpace(_newSnippetKey) || string.IsNullOrWhiteSpace(_newSnippetContent))
            return false;
        if (Snippets.Any(sn => sn.Key.Equals(_newSnippetKey.Trim(), StringComparison.OrdinalIgnoreCase)))
            return false;

        Snippets.Add(new SnippetRowModel
        {
            Key     = _newSnippetKey.Trim(),
            Name    = _newSnippetName.Trim(),
            Content = _newSnippetContent.Trim()
        });
        NewSnippetKey = ""; NewSnippetName = ""; NewSnippetContent = "";
        return true;
    }

    public void RemoveSnippet(SnippetRowModel row) => Snippets.Remove(row);

    // ─── 캡처 메서드 ────────────────────────────────────────────────────────
    public void ResetCapPrefix() => CapPrefix = "cap";

    public void ResetCapGlobalHotkey()
    {
        CapGlobalHotkey = "PrintScreen";
        CapGlobalMode   = "screen";
    }

    // ─── 알림 메서드 ────────────────────────────────────────────────────────
    public List<string> GetReminderCategories() => _service.Settings.Reminder.EnabledCategories;

    // ─── 시스템 명령 메서드 ─────────────────────────────────────────────────
    public void ResetSystemCommandAliases()
    {
        AliasLock = ""; AliasSleep = ""; AliasRestart = "";
        AliasShutdown = ""; AliasHibernate = ""; AliasLogout = ""; AliasRecycle = "";
    }

    private static string FormatAliases(Dictionary<string, List<string>> dict, string key)
        => dict.TryGetValue(key, out var list) ? string.Join(", ", list) : "";

    private static List<string> ParseAliases(string input)
        => input.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
                .Where(s => !string.IsNullOrWhiteSpace(s))
                .ToList();

    public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
    protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string? n = null)
        => PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(n));
}
