using System.Windows;
using AxCopilot.Models;
using AxCopilot.Services;
using AxCopilot.Services.Agent;
using AxCopilot.Services.Agent.SlashCommands;

namespace AxCopilot.Views;

/// <summary>
/// Phase 18: SlashCommandRegistry IAgentChatContext 구현.
/// ChatWindow가 IAgentChatContext를 구현하여 SlashCommandRegistry 명령에
/// LLM, 설정, UI 조작 기능을 제공합니다.
/// </summary>
public partial class ChatWindow : IAgentChatContext
{
    // ─── SlashCommandRegistry 연결 ──────────────────────────────────────────

    private readonly SlashCommandRegistry _slashRegistry = SlashCommandRegistry.CreateDefault();

    // IAgentChatContext 구현

    LlmService IAgentChatContext.Llm => _llm;

    SettingsService IAgentChatContext.Settings => _settings;

    IReadOnlyList<SkillDefinition> IAgentChatContext.LoadedSkills => SkillService.Skills;

    IReadOnlyList<ExtendedHookEntry> IAgentChatContext.Hooks
    {
        get
        {
            var cfg = _settings.Settings.Llm.ExtendedHooks;
            var allHooks = new List<ExtendedHookEntry>();

            void AddHooks(IEnumerable<ExtendedHookEntryConfig>? configs, HookEventKind kind)
            {
                if (configs == null) return;
                foreach (var c in configs.Where(x => x.Enabled))
                    allHooks.Add(new ExtendedHookEntry
                    {
                        Name           = c.Name,
                        Event          = kind,
                        Matcher        = c.Matcher,
                        Mode           = ParseHookMode(c.Mode),
                        ScriptPath     = c.ScriptPath,
                        Url            = c.Url,
                        Prompt         = c.Prompt,
                        Model          = c.Model,
                        Enabled        = c.Enabled,
                        Once           = c.Once,
                        IsAsync        = c.IsAsync,
                        TimeoutSeconds = c.TimeoutSeconds > 0 ? c.TimeoutSeconds : 30,
                        StatusMessage  = c.StatusMessage,
                    });
            }

            AddHooks(cfg.PreToolUse,        HookEventKind.PreToolUse);
            AddHooks(cfg.PostToolUse,        HookEventKind.PostToolUse);
            AddHooks(cfg.PostToolUseFailure, HookEventKind.PostToolUseFailure);
            AddHooks(cfg.SessionStart,       HookEventKind.SessionStart);
            AddHooks(cfg.SessionEnd,         HookEventKind.SessionEnd);
            AddHooks(cfg.UserPromptSubmit,   HookEventKind.UserPromptSubmit);
            AddHooks(cfg.AgentStop,          HookEventKind.AgentStop);
            AddHooks(cfg.PreCompact,         HookEventKind.PreCompact);
            AddHooks(cfg.PostCompact,        HookEventKind.PostCompact);
            AddHooks(cfg.FileChanged,        HookEventKind.FileChanged);

            return allHooks;
        }
    }

    string IAgentChatContext.ActiveTab => _activeTab;

    string IAgentChatContext.WorkFolder => GetCurrentWorkFolder();

    SlashCommandRegistry IAgentChatContext.CommandRegistry => _slashRegistry;

    async Task IAgentChatContext.SendSystemMessageAsync(string message)
    {
        await Dispatcher.InvokeAsync(() =>
        {
            AddMessageBubble("assistant", $"ℹ️ {message}");
            AutoScrollIfNeeded();
        });
    }

    async Task<string?> IAgentChatContext.PromptUserAsync(string question)
    {
        string? response = null;
        await Dispatcher.InvokeAsync(() =>
        {
            response = UserAskDialog.Show(question, new System.Collections.Generic.List<string>());
        });
        return response;
    }

    void IAgentChatContext.ClearMessages()
    {
        Dispatcher.Invoke(() =>
        {
            MessagePanel.Children.Clear();
            EmptyState.Visibility = Visibility.Visible;
            lock (_convLock)
            {
                _currentConversation?.Messages.Clear();
            }
        });
    }

    void IAgentChatContext.UpdateSessionHeader()
    {
        Dispatcher.Invoke(() =>
        {
            UpdateModelLabel();
            UpdatePlanModeUI();
        });
    }

    void IAgentChatContext.ToggleSettingsPanel() => Dispatcher.Invoke(ToggleSettingsPanel);

    // ─── SlashCommandRegistry → ChatWindow 팝업 통합 ──────────────────────

    /// <summary>
    /// SlashCommandRegistry 명령을 팝업 후보 목록에 추가합니다.
    /// ChatWindow.SlashCommands.cs의 InputBox_TextChanged에서 호출됩니다.
    /// </summary>
    internal IEnumerable<(string Cmd, string Label, bool IsSkill)> GetRegistrySlashMatches(string prefix)
    {
        return _slashRegistry.GetAll()
            .Where(c => ("/" + c.Name).StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            .Select(c => (
                Cmd: "/" + c.Name,
                Label: c.Description,
                IsSkill: false
            ));
    }

    /// <summary>
    /// 입력 텍스트가 SlashCommandRegistry 명령이면 실행합니다.
    /// 실행 성공 시 true 반환.
    /// </summary>
    internal async Task<bool> TryExecuteRegistrySlashCommandAsync(
        string fullInput, CancellationToken ct)
    {
        // "/compact 추가 지시사항" → name="compact", args="추가 지시사항"
        var trimmed = fullInput.TrimStart('/');
        var spaceIdx = trimmed.IndexOf(' ');
        var name = spaceIdx >= 0 ? trimmed[..spaceIdx] : trimmed;
        var args = spaceIdx >= 0 ? trimmed[(spaceIdx + 1)..].Trim() : "";

        var command = _slashRegistry.Resolve("/" + name);
        if (command == null) return false;

        try
        {
            _isStreaming = true;
            Dispatcher.Invoke(() => BtnSend.IsEnabled = false);
            await command.ExecuteAsync(args, this, ct);
        }
        catch (OperationCanceledException) { /* 취소 */ }
        catch (Exception ex)
        {
            await ((IAgentChatContext)this).SendSystemMessageAsync($"명령 실행 오류: {ex.Message}");
        }
        finally
        {
            _isStreaming = false;
            Dispatcher.Invoke(() => BtnSend.IsEnabled = true);
        }

        return true;
    }

    // ─── 내부 헬퍼 ──────────────────────────────────────────────────────────

    private static HookExecutionMode ParseHookMode(string? mode) =>
        mode?.ToLowerInvariant() switch
        {
            "http"    => HookExecutionMode.Http,
            "prompt"  => HookExecutionMode.Prompt,
            "agent"   => HookExecutionMode.Agent,
            _         => HookExecutionMode.Command,
        };
}
