using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// 루틴 자동화 핸들러. "routine" 프리픽스로 사용합니다.
/// 등록된 루틴을 실행하면 앱·폴더·URL을 순서대로 일괄 실행합니다.
/// 예: routine              → 등록된 루틴 목록
///     routine morning      → "morning" 루틴 실행
///     routine add morning  → 루틴 추가 안내
/// 루틴 정의: %APPDATA%\AxCopilot\routines.json
/// </summary>
public class RoutineHandler : IActionHandler
{
    public string? Prefix => "routine";

    public PluginMetadata Metadata => new(
        "Routine",
        "루틴 자동화 — routine",
        "1.0",
        "AX");

    private static readonly string RoutineFile = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "routines.json");

    private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true, PropertyNameCaseInsensitive = true };

    // 내장 기본 루틴
    private static readonly RoutineDefinition[] BuiltInRoutines =
    [
        new("morning", "출근 루틴", [
            new("app",    "explorer.exe",     "파일 탐색기"),
            new("info",   "info",             "시스템 정보 표시"),
        ]),
        new("endofday", "퇴근 루틴", [
            new("cmd",    "journal",          "오늘 업무 일지 생성"),
        ]),
    ];

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var q = query.Trim();
        var all = LoadRoutines();

        if (string.IsNullOrWhiteSpace(q))
        {
            var items = new List<LauncherItem>
            {
                new("루틴 자동화",
                    $"총 {all.Count}개 루틴  ·  이름 입력 시 실행  ·  routines.json에서 편집",
                    null, null, Symbol: Symbols.Info)
            };

            foreach (var r in all)
            {
                var steps = string.Join(" → ", r.Steps.Select(s => s.Label));
                items.Add(new LauncherItem(
                    $"[{r.Name}]  {r.Description}",
                    $"{r.Steps.Length}단계: {steps}  ·  Enter로 실행",
                    null, r,
                    Symbol: Symbols.Lightbulb));
            }

            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 루틴 검색/실행
        var match = all.FirstOrDefault(r =>
            r.Name.Equals(q, StringComparison.OrdinalIgnoreCase));

        if (match != null)
        {
            var steps = string.Join(" → ", match.Steps.Select(s => s.Label));
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    $"[{match.Name}] 루틴 실행",
                    $"{match.Description}  ·  {steps}",
                    null, match,
                    Symbol: Symbols.Lightbulb)
            ]);
        }

        // 부분 매칭
        var filtered = all.Where(r =>
            r.Name.Contains(q, StringComparison.OrdinalIgnoreCase) ||
            r.Description.Contains(q, StringComparison.OrdinalIgnoreCase));

        var result = filtered.Select(r => new LauncherItem(
            $"[{r.Name}]  {r.Description}",
            $"{r.Steps.Length}단계  ·  Enter로 실행",
            null, r,
            Symbol: Symbols.Lightbulb)).ToList<LauncherItem>();

        if (!result.Any())
        {
            result.Add(new LauncherItem(
                $"'{q}' 루틴 없음",
                $"routines.json에서 직접 추가하거나 routine으로 목록 확인",
                null, null, Symbol: Symbols.Warning));
        }

        return Task.FromResult<IEnumerable<LauncherItem>>(result);
    }

    public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is not RoutineDefinition routine) return;

        int executed = 0;
        foreach (var step in routine.Steps)
        {
            try
            {
                switch (step.Type.ToLowerInvariant())
                {
                    case "app":
                    case "url":
                    case "folder":
                        Process.Start(new ProcessStartInfo(step.Target) { UseShellExecute = true });
                        break;
                    case "cmd":
                        // PowerShell 명령 실행
                        Process.Start(new ProcessStartInfo("powershell.exe", $"-Command \"{step.Target}\"")
                            { UseShellExecute = false, CreateNoWindow = true });
                        break;
                    case "info":
                        // 알림으로 대체
                        NotificationService.Notify("루틴", step.Label);
                        break;
                }
                executed++;
                await Task.Delay(300, ct); // 앱 간 간격
            }
            catch (Exception ex)
            {
                LogService.Warn($"루틴 단계 실행 실패: {step.Label} — {ex.Message}");
            }
        }

        NotificationService.Notify("루틴 완료", $"[{routine.Name}] {executed}/{routine.Steps.Length}단계 실행 완료");
    }

    private List<RoutineDefinition> LoadRoutines()
    {
        var list = new List<RoutineDefinition>(BuiltInRoutines);

        try
        {
            if (File.Exists(RoutineFile))
            {
                var json = File.ReadAllText(RoutineFile);
                var user = JsonSerializer.Deserialize<List<RoutineDefinition>>(json, JsonOpts);
                if (user != null)
                {
                    // 사용자 루틴이 내장 루틴을 오버라이드
                    foreach (var r in user)
                    {
                        list.RemoveAll(x => x.Name.Equals(r.Name, StringComparison.OrdinalIgnoreCase));
                        list.Add(r);
                    }
                }
            }
        }
        catch (Exception ex) { LogService.Warn($"루틴 로드 실패: {ex.Message}"); }

        return list;
    }

    internal record RoutineDefinition(
        [property: JsonPropertyName("name")] string Name,
        [property: JsonPropertyName("description")] string Description,
        [property: JsonPropertyName("steps")] RoutineStep[] Steps);

    internal record RoutineStep(
        [property: JsonPropertyName("type")] string Type,
        [property: JsonPropertyName("target")] string Target,
        [property: JsonPropertyName("label")] string Label);
}
