using System.Windows;
using System.Windows.Forms;
using Microsoft.Win32;
using AxCopilot.Core;
using AxCopilot.Handlers;
using AxCopilot.Services;
using AxCopilot.Services.Agent;
using AxCopilot.ViewModels;
using AxCopilot.Views;

namespace AxCopilot;

public partial class App : System.Windows.Application
{
    private System.Threading.Mutex?   _singleInstanceMutex;
    private InputListener?            _inputListener;
    private LauncherWindow?           _launcher;
    private NotifyIcon?               _trayIcon;
    private Views.TrayMenuWindow?     _trayMenu;
    private SettingsService?          _settings;
    private SettingsWindow?           _settingsWindow;
    private PluginHost?               _pluginHost;
    private SchedulerService?         _schedulerService;
    private ClipboardHistoryService?  _clipboardHistory;
    private DockBarWindow?            _dockBar;
    private FileDialogWatcher?        _fileDialogWatcher;
    private volatile IndexService?    _indexService;
    public  IndexService?             IndexService    => _indexService;
    public  SettingsService?          SettingsService => _settings;
    public  ClipboardHistoryService? ClipboardHistoryService => _clipboardHistory;
    private SessionTrackingService?   _sessionTracking;
    private WorktimeReminderService?  _worktimeReminder;
    private ScreenCaptureHandler?     _captureHandler;
    private AgentMemoryService?       _memoryService;
    public  AgentMemoryService?       MemoryService => _memoryService;
    private LlmService?               _sharedLlm;
    private PluginInstallService?     _pluginInstallService;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // ─── 보안: 디버거/디컴파일러 감지 (Release 빌드만 활성) ───
        Security.AntiTamper.Check();

        // 전역 예외 핸들러 — 미처리 예외 시 로그 + 메시지 (크래시 방지)
        DispatcherUnhandledException += (_, ex) =>
        {
            LogService.Error($"미처리 예외: {ex.Exception}");
            CustomMessageBox.Show(
                $"오류가 발생했습니다:\n{ex.Exception.Message}\n\n로그 폴더를 확인하세요.",
                "AX Copilot 오류", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
            ex.Handled = true;
        };

        // ─── 중복 실행 방지 ──────────────────────────────────────────────────
        _singleInstanceMutex = new System.Threading.Mutex(
            initiallyOwned: true, "Global\\AXCopilot_SingleInstance", out bool createdNew);
        if (!createdNew)
        {
            _singleInstanceMutex.Dispose();
            _singleInstanceMutex = null;
            CustomMessageBox.Show("AX Copilot가 이미 실행 중입니다.\n트레이 아이콘을 확인하세요.",
                "AX Copilot", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
            Shutdown();
            return;
        }

        LogService.Info("=== AX Copilot 시작 ===");

        // ─── 서비스 초기화 ────────────────────────────────────────────────────
        _settings = new SettingsService();
        var settings = _settings;
        settings.Load();

        // Phase L3 공유 서비스
        _sharedLlm           = new LlmService(settings);
        _pluginInstallService = new PluginInstallService();

        // 마이그레이션 알림 (UI가 준비된 후 표시)
        if (settings.MigrationSummary != null)
        {
            Dispatcher.BeginInvoke(() =>
            {
                CustomMessageBox.Show(
                    settings.MigrationSummary,
                    "AX Copilot — 설정 업데이트",
                    System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Information);
            }, System.Windows.Threading.DispatcherPriority.Loaded);
        }

        // 언어 초기화
        L10n.SetLanguage(settings.Settings.Launcher.Language);

        // 첫 실행 시 자동 시작 등록 (레지스트리에 아직 없으면)
        if (!IsAutoStartEnabled())
            SetAutoStart(true);

        _memoryService = new AgentMemoryService();
        _memoryService.Load(settings.Settings.Llm.WorkFolder);

        _indexService = new IndexService(settings);
        var indexService = _indexService;
        var fuzzyEngine = new FuzzyEngine(indexService);
        var commandResolver = new CommandResolver(fuzzyEngine, settings);
        var contextManager = new ContextManager(settings);

        // ─── 세션 추적 / 사용 통계 ────────────────────────────────────────────
        _sessionTracking = new SessionTrackingService();

        // ─── 잠금 해제 알림 서비스 ────────────────────────────────────────────
        _worktimeReminder = new WorktimeReminderService(settings, Dispatcher);

        // ─── 클립보드 히스토리 서비스 ──────────────────────────────────────────
        _clipboardHistory = new ClipboardHistoryService(settings);

        // ─── 빌트인 핸들러 등록 ──────────────────────────────────────────────
        commandResolver.RegisterHandler(new CalculatorHandler());
        commandResolver.RegisterHandler(new SystemCommandHandler(settings));
        commandResolver.RegisterHandler(new SnippetHandler(settings));
        commandResolver.RegisterHandler(new ClipboardHistoryHandler(_clipboardHistory));
        commandResolver.RegisterHandler(new WorkspaceHandler(contextManager, settings));
        commandResolver.RegisterHandler(new UrlAliasHandler(settings));
        commandResolver.RegisterHandler(new FolderAliasHandler(settings));
        commandResolver.RegisterHandler(new BatchHandler(settings));
        commandResolver.RegisterHandler(new ClipboardHandler(settings));
        commandResolver.RegisterHandler(new BookmarkHandler());
        commandResolver.RegisterHandler(new WebSearchHandler(settings));
        commandResolver.RegisterHandler(new ProcessHandler());
        commandResolver.RegisterHandler(new MediaHandler());
        commandResolver.RegisterHandler(new SystemInfoHandler());
        commandResolver.RegisterHandler(new StarInfoHandler()); // * 단축키 (info와 동일)
        commandResolver.RegisterHandler(new EmojiHandler());
        commandResolver.RegisterHandler(new ColorHandler());
        commandResolver.RegisterHandler(new RecentFilesHandler());
        commandResolver.RegisterHandler(new NoteHandler());
        commandResolver.RegisterHandler(new UninstallHandler());
        commandResolver.RegisterHandler(new PortHandler());
        commandResolver.RegisterHandler(new EnvHandler());
        commandResolver.RegisterHandler(new JsonHandler());
        commandResolver.RegisterHandler(new EncodeHandler());
        commandResolver.RegisterHandler(new SnapHandler());
        _captureHandler = new ScreenCaptureHandler(settings);
        commandResolver.RegisterHandler(_captureHandler);
        commandResolver.RegisterHandler(new ColorPickHandler());
        commandResolver.RegisterHandler(new DateCalcHandler());
        commandResolver.RegisterHandler(new ServiceHandler(_clipboardHistory));
        commandResolver.RegisterHandler(new ClipboardPipeHandler());
        commandResolver.RegisterHandler(new JournalHandler());
        commandResolver.RegisterHandler(new RoutineHandler());
        commandResolver.RegisterHandler(new BatchTextHandler());
        commandResolver.RegisterHandler(new DiffHandler(_clipboardHistory));
        commandResolver.RegisterHandler(new WindowSwitchHandler());
        commandResolver.RegisterHandler(new RunHandler());
        commandResolver.RegisterHandler(new TextStatsHandler());
        commandResolver.RegisterHandler(new FavoriteHandler());
        commandResolver.RegisterHandler(new RenameHandler());
        commandResolver.RegisterHandler(new MonitorHandler());
        commandResolver.RegisterHandler(new ScaffoldHandler());
        commandResolver.RegisterHandler(new EverythingHandler());
        commandResolver.RegisterHandler(new HelpHandler(settings));
        commandResolver.RegisterHandler(new ChatHandler(settings));

        // ─── Phase L3 핸들러 ──────────────────────────────────────────────────
        commandResolver.RegisterHandler(new QuickLinkHandler(settings));
        var snippetTemplateSvc = new SnippetTemplateService(settings, _sharedLlm);
        commandResolver.RegisterHandler(new AiSnippetHandler(settings, snippetTemplateSvc));
        commandResolver.RegisterHandler(new WebSearchSummaryHandler(settings, _sharedLlm));
        // Phase L3-5: 파일 태그 시스템
        commandResolver.RegisterHandler(new TagHandler());
        // Phase L3-8: 알림 센터
        commandResolver.RegisterHandler(new NotifHandler());
        // Phase L3-9: 뽀모도로 타이머
        commandResolver.RegisterHandler(new PomoHandler());

        // ─── Phase L4 핸들러 ──────────────────────────────────────────────────
        // Phase L4-1: 인라인 파일 탐색기 (Prefix=null, 경로 패턴 감지)
        commandResolver.RegisterHandler(new FileBrowserHandler());

        // ─── Phase L5 핸들러 ──────────────────────────────────────────────────
        // Phase L5-1: 전용 핫키 목록 관리 (prefix=hotkey)
        commandResolver.RegisterHandler(new HotkeyHandler(settings));
        // Phase L5-2: OCR 화면 텍스트 추출 (prefix=ocr)
        commandResolver.RegisterHandler(new OcrHandler());
        // Phase L5-4: 앱 세션 스냅 (prefix=session)
        commandResolver.RegisterHandler(new SessionHandler(settings));
        // Phase L5-5: 배치 파일 이름변경 (prefix=batchren)
        commandResolver.RegisterHandler(new BatchRenameHandler());
        // Phase L5-6: 자동화 스케줄러 (prefix=sched)
        var schedulerService = new SchedulerService(settings);
        schedulerService.Start();
        _schedulerService = schedulerService;
        commandResolver.RegisterHandler(new ScheduleHandler(settings));
        // Phase L6-2: 런처 매크로 (prefix=macro)
        commandResolver.RegisterHandler(new MacroHandler(settings));
        // Phase L6-3: 컨텍스트 감지 자동완성 (prefix=ctx)
        commandResolver.RegisterHandler(new ContextHandler());

        // ─── Phase L7 핸들러 ──────────────────────────────────────────────────
        // L7-1: Git 빠른 조회 (prefix=git)
        commandResolver.RegisterHandler(new GitHandler());
        // L7-2: 정규식 테스터 (prefix=re)
        commandResolver.RegisterHandler(new RegexHandler());
        // L7-3: 시간대 변환기 (prefix=tz)
        commandResolver.RegisterHandler(new TimeZoneHandler());
        // L7-4: 네트워크 진단 (prefix=net)
        commandResolver.RegisterHandler(new NetDiagHandler());

        // ─── Phase L8 핸들러 ──────────────────────────────────────────────────
        // L8-1: 파일 해시 검증 (prefix=hash)
        commandResolver.RegisterHandler(new FileHashHandler());
        // L8-2: 아카이브 관리 (prefix=zip)
        commandResolver.RegisterHandler(new ZipHandler());
        // L8-3: 시스템 이벤트 로그 (prefix=evt)
        commandResolver.RegisterHandler(new EventLogHandler());
        // L8-4: SSH 퀵 커넥트 (prefix=ssh)
        commandResolver.RegisterHandler(new SshHandler(settings));

        // ─── Phase L9 핸들러 ──────────────────────────────────────────────────
        // L9-1: 비밀번호 생성기 (prefix=pwd)
        commandResolver.RegisterHandler(new PasswordGenHandler());
        // L9-2: IP 서브넷 계산기 (prefix=subnet)
        commandResolver.RegisterHandler(new SubnetHandler());
        // L9-3: 시스템 정리 (prefix=clean)
        commandResolver.RegisterHandler(new CleanHandler());
        // L9-4: 진수 변환기 (prefix=base)
        commandResolver.RegisterHandler(new BaseConvertHandler());

        // ─── Phase L10 핸들러 ─────────────────────────────────────────────────
        // L10-1: XML 포맷터·검증기·XPath (prefix=xml)
        commandResolver.RegisterHandler(new XmlHandler());
        // L10-2: UUID/GUID 생성기 (prefix=uuid)
        commandResolver.RegisterHandler(new UuidHandler());
        // L10-3: SSL 인증서 체커 (prefix=cert)
        commandResolver.RegisterHandler(new CertHandler());
        // L10-4: Lorem Ipsum 더미 텍스트 (prefix=lorem)
        commandResolver.RegisterHandler(new LoremHandler());

        // ─── Phase L11 핸들러 ─────────────────────────────────────────────────
        // L11-1: CSV 뷰어·파서 (prefix=csv)
        commandResolver.RegisterHandler(new CsvHandler());
        // L11-2: JWT 토큰 디코더 (prefix=jwt)
        commandResolver.RegisterHandler(new JwtHandler());
        // L11-3: Cron 표현식 설명기 (prefix=cron)
        commandResolver.RegisterHandler(new CronHandler());
        // L11-4: 유니코드 문자 조회 (prefix=unicode)
        commandResolver.RegisterHandler(new UnicodeHandler());

        // ─── Phase L12 핸들러 ─────────────────────────────────────────────────
        // L12-1: HTTP 요청 테스터 (prefix=http)
        commandResolver.RegisterHandler(new HttpTesterHandler());
        // L12-2: hosts 파일 관리 (prefix=hosts)
        commandResolver.RegisterHandler(new HostsHandler());
        // L12-3: 모스 부호 변환기 (prefix=morse)
        commandResolver.RegisterHandler(new MorseHandler());
        // L12-4: 시작 프로그램 조회 (prefix=startup)
        commandResolver.RegisterHandler(new StartupHandler());

        // ─── Phase L13 핸들러 ─────────────────────────────────────────────────
        // L13-1: DNS 레코드 조회 (prefix=dns)
        commandResolver.RegisterHandler(new DnsQueryHandler());
        // L13-2: PATH 환경변수 뷰어 (prefix=path)
        commandResolver.RegisterHandler(new PathHandler());
        // L13-3: 드라이브 정보 (prefix=drive)
        commandResolver.RegisterHandler(new DriveHandler());
        // L13-4: 나이·D-day 계산기 (prefix=age)
        commandResolver.RegisterHandler(new AgeHandler());

        // ─── Phase L14 핸들러 ─────────────────────────────────────────────────
        // L14-1: Wake-on-LAN (prefix=wol)
        commandResolver.RegisterHandler(new WolHandler());
        // L14-2: 레지스트리 조회 (prefix=reg)
        commandResolver.RegisterHandler(new RegHandler());
        // L14-3: 팁·할인·분할 계산기 (prefix=tip)
        commandResolver.RegisterHandler(new TipHandler());
        // L14-4: 시스템 폰트 목록 (prefix=font)
        commandResolver.RegisterHandler(new FontHandler());

        // ─── Phase L15 핸들러 ─────────────────────────────────────────────────
        // L15-1: WSL 관리 (prefix=wsl)
        commandResolver.RegisterHandler(new WslHandler());
        // L15-2: 환율 변환기 (prefix=currency)
        commandResolver.RegisterHandler(new CurrencyHandler());
        // L15-3: BMI·건강 계산기 (prefix=bmi)
        commandResolver.RegisterHandler(new BmiHandler());
        // L15-4: Markdown 분석기 (prefix=md)
        commandResolver.RegisterHandler(new MdHandler());

        // ─── Phase L16 핸들러 ─────────────────────────────────────────────────
        // L16-1: ping·tracert 실행기 (prefix=ping)
        commandResolver.RegisterHandler(new PingHandler());
        // L16-2: Docker 컨테이너·이미지 조회 (prefix=docker)
        commandResolver.RegisterHandler(new DockerHandler());
        // L16-3: 할 일 목록 (prefix=todo)
        commandResolver.RegisterHandler(new TodoHandler());
        // L16-4: 텍스트 → 표 변환기 (prefix=table)
        commandResolver.RegisterHandler(new TableHandler());

        // ─── Phase L17 핸들러 ─────────────────────────────────────────────────
        // L17-1: 단위 변환기 (prefix=unit)
        commandResolver.RegisterHandler(new UnitHandler());
        // L17-2: 숫자 포맷·읽기 변환기 (prefix=num)
        commandResolver.RegisterHandler(new NumHandler());
        // L17-3: YAML 파서·포맷터 (prefix=yaml)
        commandResolver.RegisterHandler(new YamlHandler());
        // L17-4: .gitignore 생성기 (prefix=gitignore)
        commandResolver.RegisterHandler(new GitignoreHandler());

        // ─── Phase L18 핸들러 ─────────────────────────────────────────────────
        // L18-1: SQL 포맷터·분석기 (prefix=sql)
        commandResolver.RegisterHandler(new SqlHandler());
        // L18-2: 텍스트 케이스 변환기 (prefix=text)
        commandResolver.RegisterHandler(new TextCaseHandler());
        // L18-3: 화면 비율·해상도 계산기 (prefix=aspect)
        commandResolver.RegisterHandler(new AspectHandler());
        // L18-4: IT·개발 약어 사전 (prefix=abbr)
        commandResolver.RegisterHandler(new AbbrHandler());
        // L19-1: 공학 계산기 (prefix=calc)
        commandResolver.RegisterHandler(new CalcHandler());
        // L19-2: 타이머·알람 (prefix=timer)
        commandResolver.RegisterHandler(new TimerHandler());
        // L19-3: IP 주소 유틸리티 (prefix=ip)
        commandResolver.RegisterHandler(new IpInfoHandler());
        // L19-4: npm/yarn/pnpm 명령어 생성기 (prefix=npm)
        commandResolver.RegisterHandler(new NpmHandler());
        // L20-1: 16진수·바이트 변환기 (prefix=hex)
        commandResolver.RegisterHandler(new HexHandler());
        // L20-2: 랜덤 생성기 (prefix=rand)
        commandResolver.RegisterHandler(new RandHandler());
        // L20-3: 문자열 조작 도구 (prefix=str)
        commandResolver.RegisterHandler(new StrHandler());
        // L20-4: Unix 파일 권한 계산기 (prefix=perm)
        commandResolver.RegisterHandler(new PermHandler());
        // L21-1: TOML 파서·분석기 (prefix=toml)
        commandResolver.RegisterHandler(new TomlHandler());
        // L21-2: 로그 파일 분석기 (prefix=log)
        commandResolver.RegisterHandler(new LogHandler());
        // L21-3: PowerShell 명령 생성기 (prefix=ps)
        commandResolver.RegisterHandler(new PsHandler());
        // L21-4: 키보드 단축키 참조 사전 (prefix=key)
        commandResolver.RegisterHandler(new KeyHandler());

        // L22-1: 프로세스 상세 조회·정리 (prefix=proc)
        commandResolver.RegisterHandler(new ProcHandler());
        // L22-2: Excel 함수 레퍼런스 (prefix=xl)
        commandResolver.RegisterHandler(new XlHandler());
        // L22-3: Python pip 명령 생성기 (prefix=pip)
        commandResolver.RegisterHandler(new PipHandler());
        // L22-4: 업무 양식·문서 구조 템플릿 (prefix=form)
        commandResolver.RegisterHandler(new FormHandler());

        // ─── L23: 한국 사무 환경 특화 ─────────────────────────────────────
        // L23-1: 한국 공휴일·업무일 달력 (prefix=cal)
        commandResolver.RegisterHandler(new CalHandler());
        // L23-2: 연차·휴가 관리 (prefix=leave)
        commandResolver.RegisterHandler(new LeaveHandler());
        // L23-3: 근무 시간·급여 계산 (prefix=work)
        commandResolver.RegisterHandler(new WorkTimeHandler());
        // L23-4: 한/영 타이핑 오류 교정 (prefix=fix)
        commandResolver.RegisterHandler(new FixHandler());
        // L24-3: 자주 틀리는 맞춤법 (prefix=spell)
        commandResolver.RegisterHandler(new SpellHandler());

        // ─── L25: 개인 생산성 강화 ─────────────────────────────────────────────
        // L25-1: 로컬 연락처 관리 (prefix=contact)
        commandResolver.RegisterHandler(new ContactHandler());
        // L25-2: 오늘 특정 시각 알림 (prefix=remind)
        commandResolver.RegisterHandler(new RemindHandler());
        // L25-3: 자주 쓰는 업무 문구 (prefix=phrase)
        commandResolver.RegisterHandler(new PhraseHandler());
        // L25-4: 오늘 업무 통합 뷰 (prefix=today)
        commandResolver.RegisterHandler(new TodayHandler());

        // ─── L27: 경쟁 공백 즉시 해소 ────────────────────────────────────────
        // L27-1: 브라우저 북마크 검색 — BookmarkHandler (기구현, prefix=null 퍼지 통합)
        // L27-2: 시스템 볼륨 제어 (prefix=vol)
        commandResolver.RegisterHandler(new VolHandler());
        // L27-3: QR 코드 생성 (prefix=qr)
        commandResolver.RegisterHandler(new QrHandler());
        // L27-4: 회의 링크 관리 (prefix=meet)
        commandResolver.RegisterHandler(new MeetHandler());
        // L27-5: 화면 밝기 제어 (prefix=bright)
        commandResolver.RegisterHandler(new BrightHandler());
        // L27-6: 클립보드 순차 붙여넣기 (prefix=paste)
        commandResolver.RegisterHandler(new PasteHandler(_clipboardHistory));

        // ─── L28: Windows 생태계 통합 + 콘텐츠 UX 강화 ─────────────────────
        // L28-1: winget 앱 검색·설치 (prefix=pkg)
        commandResolver.RegisterHandler(new PkgHandler());
        // L28-2: SnippetHandler 동적 플레이스홀더 확장 — {clipboard}/{user}/{app}/{weekday}/{computer} 추가 (기존 핸들러 수정)
        // L28-3: 파일 미리보기 강화 — 이미지 해상도·PDF 페이지수·미디어 메타 (LauncherViewModel 수정)
        // L28-4: 클립보드 텍스트 즉시 변환 (prefix=ap)
        commandResolver.RegisterHandler(new ApHandler());

        // ─── L29: AX 차별화 심화 ─────────────────────────────────────────────
        // L29-1: 오프라인 국어·영한 사전 (prefix=dict)
        commandResolver.RegisterHandler(new DictHandler());
        // L29-2: 명령 체인 워크플로우 (prefix=flow)
        commandResolver.RegisterHandler(new FlowHandler());
        // L29-3: SpellHandler 사용자 항목 추가 — spell add/del/custom 명령 (기존 핸들러 수정)
        // L29-4: BookmarkHandler 결과에 Group="📑 북마크" 카테고리 헤더 추가 (기존 핸들러 수정)

        // ─── 플러그인 로드 ────────────────────────────────────────────────────
        var pluginHost = new PluginHost(settings, commandResolver);
        pluginHost.LoadAll();
        _pluginHost = pluginHost;

        // ─── 런처 윈도우 ──────────────────────────────────────────────────────
        var vm = new LauncherViewModel(commandResolver, settings);
        _launcher = new LauncherWindow(vm)
        {
            OpenSettingsAction = OpenSettings
        };

        // ─── 클립보드 히스토리 초기화 (메시지 펌프 시작 직후 — 런처 표시 불필요) ──
        Dispatcher.BeginInvoke(
            () => _clipboardHistory?.Initialize(),
            System.Windows.Threading.DispatcherPriority.ApplicationIdle);

        // ─── 파일 아이콘 캐시 워밍업 (앱 유휴 시점에 자주 쓰는 확장자 미리 추출) ──
        Dispatcher.BeginInvoke(
            () => AxCopilot.Services.IconCacheService.WarmUp(),
            System.Windows.Threading.DispatcherPriority.SystemIdle);

        // ─── ChatWindow 미리 생성 (앱 유휴 시점에 숨겨진 채로 초기화) ──────────
        // 이후 OpenAiChat() 시 창 생성 비용 없이 즉시 열림
        Dispatcher.BeginInvoke(
            () => PrewarmChatWindow(),
            System.Windows.Threading.DispatcherPriority.SystemIdle);

        // ─── 인덱스 빌드 (백그라운드) + 완료 후 FileSystemWatcher 시작 ────────
        _ = indexService.BuildAsync().ContinueWith(_ => indexService.StartWatchers());

        // ─── 글로벌 훅 + 스니펫 확장기 ───────────────────────────────────────
        _inputListener = new InputListener();
        _inputListener.HotkeyTriggered += OnHotkeyTriggered;
        _inputListener.CaptureHotkeyTriggered += OnCaptureHotkeyTriggered;
        _inputListener.CustomHotkeyTriggered += OnCustomHotkeyTriggered;
        _inputListener.HookFailed += OnHookFailed;

        // 설정에 저장된 핫키로 초기화 (기본: Alt+Space)
        _inputListener.UpdateHotkey(settings.Settings.Hotkey);

        // 글로벌 캡처 단축키 초기화
        _inputListener.UpdateCaptureHotkey(
            settings.Settings.ScreenCapture.GlobalHotkey,
            settings.Settings.ScreenCapture.GlobalHotkeyEnabled);

        // 항목별 전용 핫키 초기화
        _inputListener.UpdateCustomHotkeys(settings.Settings.CustomHotkeys);

        var snippetExpander = new SnippetExpander(settings);
        _inputListener.KeyFilter = snippetExpander.HandleKey;

        _inputListener.Start();

        // ─── 시스템 트레이 ─────────────────────────────────────────────────────
        SetupTrayIcon(pluginHost, settings);

        // ─── 파일 대화상자 감지 ──────────────────────────────────────────────
        _fileDialogWatcher = new FileDialogWatcher();
        _fileDialogWatcher.FileDialogOpened += (_, hwnd) =>
        {
            Dispatcher.Invoke(() =>
            {
                if (_launcher == null || _launcher.IsVisible) return;
                if (_settings?.Settings.Launcher.EnableFileDialogIntegration != true) return;
                WindowTracker.Capture();
                _launcher.Show();
                Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input,
                    () => _launcher.SetInputText("cd "));
            });
        };
        _fileDialogWatcher.Start();

        // 독 바 자동 표시
        if (settings.Settings.Launcher.DockBarAutoShow)
            Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Loaded, () => ToggleDockBar());

        LogService.Info($"초기화 완료. {settings.Settings.Hotkey}로 실행하세요.");
    }

    private void OnHotkeyTriggered(object? sender, EventArgs e)
    {
        // 런처가 열리기 전 현재 활성 창을 저장 (SnapHandler, ScreenCaptureHandler용)
        WindowTracker.Capture();

        // 선택 텍스트 감지는 UI 스레드 밖에서 수행해야 SendInput이 정상 처리됨
        var launcherSettings = _settings?.Settings.Launcher;
        var enableTextAction = launcherSettings?.EnableTextAction == true;

        // ── 런처 토글(닫기)은 텍스트 감지 없이 즉시 처리 ──
        bool isVisible = false;
        Dispatcher.Invoke(() => { isVisible = _launcher?.IsVisible == true; });
        if (isVisible)
        {
            Dispatcher.Invoke(() => _launcher?.Hide());
            return;
        }

        // ── 텍스트 감지가 비활성이면 즉시 런처 표시 ──
        if (!enableTextAction)
        {
            Dispatcher.Invoke(() =>
            {
                if (_launcher == null) return;
                UsageStatisticsService.RecordLauncherOpen();
                _launcher.Show();
            });
            return;
        }

        // ── 텍스트 감지 활성: 런처를 먼저 열고, 텍스트 감지를 비동기로 처리 ──
        string? selectedText = TryGetSelectedText();

        Dispatcher.Invoke(() =>
        {
            if (_launcher == null) return;

            if (!string.IsNullOrWhiteSpace(selectedText))
            {
                var enabledCmds = launcherSettings?.TextActionCommands ?? new();

                // 활성 명령이 1개뿐이면 팝업 없이 바로 실행
                if (enabledCmds.Count == 1)
                {
                    var directAction = TextActionPopup.AvailableCommands
                        .FirstOrDefault(c => c.Key == enabledCmds[0]);
                    if (!string.IsNullOrEmpty(directAction.Key))
                    {
                        var actionResult = enabledCmds[0] switch
                        {
                            "translate" => TextActionPopup.ActionResult.Translate,
                            "summarize" => TextActionPopup.ActionResult.Summarize,
                            "grammar"   => TextActionPopup.ActionResult.GrammarFix,
                            "explain"   => TextActionPopup.ActionResult.Explain,
                            "rewrite"   => TextActionPopup.ActionResult.Rewrite,
                            _           => TextActionPopup.ActionResult.None,
                        };
                        if (actionResult != TextActionPopup.ActionResult.None)
                        {
                            ExecuteTextAction(actionResult, selectedText);
                            return;
                        }
                    }
                }

                // 여러 개 → 팝업 표시
                var popup = new TextActionPopup(selectedText, enabledCmds);
                popup.Closed += (_, _) =>
                {
                    switch (popup.SelectedAction)
                    {
                        case TextActionPopup.ActionResult.OpenLauncher:
                            UsageStatisticsService.RecordLauncherOpen();
                            _launcher.Show();
                            break;
                        case TextActionPopup.ActionResult.None:
                            break; // Esc 또는 포커스 잃음
                        default:
                            // AI 명령 실행 → AX Agent 대화로 전달
                            ExecuteTextAction(popup.SelectedAction, popup.SelectedText);
                            break;
                    }
                };
                popup.Show();
            }
            else
            {
                UsageStatisticsService.RecordLauncherOpen();
                _launcher.Show();
            }
        });
    }

    /// <summary>현재 선택된 텍스트를 가져옵니다 (Ctrl+C 시뮬레이션).</summary>
    /// <remarks>후크 스레드에서 호출됩니다 (UI 스레드 아님). 클립보드 접근은 STA 스레드가 필요합니다.</remarks>
    private string? TryGetSelectedText()
    {
        try
        {
            // 클립보드는 STA 스레드에서만 접근 가능 → Dispatcher로 읽기
            string? prevText = null;
            bool hadText = false;
            Dispatcher.Invoke(() =>
            {
                hadText = System.Windows.Clipboard.ContainsText();
                prevText = hadText ? System.Windows.Clipboard.GetText() : null;
                System.Windows.Clipboard.Clear();
            });

            System.Threading.Thread.Sleep(30);

            // Ctrl+C 시뮬레이션 (후크 스레드에서 → 대상 앱이 처리)
            var inputs = new[]
            {
                new NativeMethods.INPUT { type = 1, u = new NativeMethods.InputUnion { ki = new NativeMethods.KEYBDINPUT { wVk = 0x11 } } },
                new NativeMethods.INPUT { type = 1, u = new NativeMethods.InputUnion { ki = new NativeMethods.KEYBDINPUT { wVk = 0x43 } } },
                new NativeMethods.INPUT { type = 1, u = new NativeMethods.InputUnion { ki = new NativeMethods.KEYBDINPUT { wVk = 0x43, dwFlags = 0x0002 } } },
                new NativeMethods.INPUT { type = 1, u = new NativeMethods.InputUnion { ki = new NativeMethods.KEYBDINPUT { wVk = 0x11, dwFlags = 0x0002 } } },
            };
            NativeMethods.SendInput((uint)inputs.Length, inputs, System.Runtime.InteropServices.Marshal.SizeOf<NativeMethods.INPUT>());

            // 클립보드 업데이트 대기 (앱마다 다름)
            System.Threading.Thread.Sleep(80);

            // 클립보드에서 새 텍스트 확인 (STA 필요)
            string? selected = null;
            Dispatcher.Invoke(() =>
            {
                if (System.Windows.Clipboard.ContainsText())
                {
                    var copied = System.Windows.Clipboard.GetText();
                    if (copied != prevText && !string.IsNullOrWhiteSpace(copied))
                        selected = copied;
                }

                // 클립보드 복원
                if (selected != null && prevText != null)
                    System.Windows.Clipboard.SetText(prevText);
                else if (selected != null && !hadText)
                    System.Windows.Clipboard.Clear();
            });

            return selected;
        }
        catch (Exception)
        {
            return null;
        }
    }

    /// <summary>AI 텍스트 명령을 AX Agent 대화로 전달합니다.</summary>
    private void ExecuteTextAction(TextActionPopup.ActionResult action, string text)
    {
        var prompt = action switch
        {
            TextActionPopup.ActionResult.Translate   => $"다음 텍스트를 번역해줘:\n\n{text}",
            TextActionPopup.ActionResult.Summarize   => $"다음 텍스트를 요약해줘:\n\n{text}",
            TextActionPopup.ActionResult.GrammarFix  => $"다음 텍스트의 문법을 교정해줘:\n\n{text}",
            TextActionPopup.ActionResult.Explain     => $"다음 텍스트를 쉽게 설명해줘:\n\n{text}",
            TextActionPopup.ActionResult.Rewrite     => $"다음 텍스트를 다시 작성해줘:\n\n{text}",
            _ => text
        };

        // ! 프리픽스로 AX Agent에 전달
        _launcher?.Show();
        _launcher?.SetInputText($"! {prompt}");
    }

    private static class NativeMethods
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct INPUT { public uint type; public InputUnion u; }

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
        public struct InputUnion { [System.Runtime.InteropServices.FieldOffset(0)] public KEYBDINPUT ki; }

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; }
    }

    private void OnCaptureHotkeyTriggered(object? sender, EventArgs e)
    {
        // 런처 없이 직접 캡처 실행
        WindowTracker.Capture();
        var mode = _settings?.Settings.ScreenCapture.GlobalHotkeyMode ?? "screen";
        Dispatcher.Invoke(async () =>
        {
            if (_captureHandler == null) return;
            try
            {
                await _captureHandler.CaptureDirectAsync(mode);
            }
            catch (Exception ex)
            {
                LogService.Error($"글로벌 캡처 실패: {ex.Message}");
            }
        });
    }

    private void OnCustomHotkeyTriggered(object? sender, Core.CustomHotkeyEventArgs e)
    {
        // 전용 핫키 발동: 런처를 열지 않고 대상을 직접 실행
        Handlers.HotkeyHandler.ExecuteHotkeyTarget(e.Target, e.Type);
    }

    private void OnHookFailed(object? sender, EventArgs e)
    {
        Dispatcher.Invoke(() =>
        {
            _trayIcon?.ShowBalloonTip(3000, "AX Copilot",
                $"글로벌 단축키 등록에 실패했습니다.\n다른 앱과 {_settings?.Settings.Hotkey ?? "단축키"}가 충돌하고 있을 수 있습니다.",
                ToolTipIcon.Warning);
        });
    }
}
