using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace AxCopilot.Services.Agent;

/// <summary>세션 전체에 걸쳐 유지되는 구조화된 작업 상태 (Working Memory).</summary>
public class TaskState
{
    [JsonPropertyName("session_id")]
    public string SessionId { get; set; } = "";

    [JsonPropertyName("current_task")]
    public string CurrentTask { get; set; } = "";

    [JsonPropertyName("referenced_files")]
    public List<string> ReferencedFiles { get; set; } = new();

    [JsonPropertyName("decision_log")]
    public List<DecisionLogEntry> DecisionLog { get; set; } = new();

    [JsonPropertyName("key_facts")]
    public Dictionary<string, string> KeyFacts { get; set; } = new();

    [JsonPropertyName("context_summary")]
    public string ContextSummary { get; set; } = "";

    [JsonPropertyName("updated_at")]
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

public record DecisionLogEntry
{
    [JsonPropertyName("ts")]
    public DateTime Timestamp { get; init; } = DateTime.UtcNow;

    [JsonPropertyName("decision")]
    public string Decision { get; init; } = "";

    [JsonPropertyName("reason")]
    public string Reason { get; init; } = "";

    [JsonPropertyName("alternatives")]
    public string[] Alternatives { get; init; } = Array.Empty<string>();
}

/// <summary>
/// 대화 압축 시에도 유지되는 Working Memory 관리 서비스.
/// 저장: %APPDATA%\AxCopilot\sessions\{sessionId}\task_state.json
/// </summary>
public class TaskStateService
{
    private static readonly string BaseDir = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "sessions");

    private static readonly JsonSerializerOptions _json = new()
    {
        WriteIndented = true,
        Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
    };

    private TaskState? _current;

    public TaskState? Current => _current;

    public async Task InitializeAsync(string sessionId)
    {
        var path = GetPath(sessionId);
        if (File.Exists(path))
        {
            try
            {
                var json = await File.ReadAllTextAsync(path);
                _current = JsonSerializer.Deserialize<TaskState>(json, _json) ?? new TaskState { SessionId = sessionId };
            }
            catch (Exception)
            {
                _current = new TaskState { SessionId = sessionId };
            }
        }
        else
        {
            _current = new TaskState { SessionId = sessionId };
        }
    }

    public async Task UpdateCurrentTaskAsync(string taskDescription)
    {
        if (_current == null) return;
        _current.CurrentTask = taskDescription;
        _current.UpdatedAt = DateTime.UtcNow;
        await SaveAsync();
    }

    public async Task AddReferencedFileAsync(string filePath)
    {
        if (_current == null) return;
        if (!_current.ReferencedFiles.Contains(filePath, StringComparer.OrdinalIgnoreCase))
            _current.ReferencedFiles.Add(filePath);
        await SaveAsync();
    }

    public async Task LogDecisionAsync(string decision, string reason, string[] alternatives)
    {
        if (_current == null) return;
        _current.DecisionLog.Add(new DecisionLogEntry
        {
            Decision = decision,
            Reason = reason,
            Alternatives = alternatives
        });
        // 최대 50개 유지
        if (_current.DecisionLog.Count > 50)
            _current.DecisionLog.RemoveAt(0);
        await SaveAsync();
    }

    public async Task UpdateContextSummaryAsync(string summary)
    {
        if (_current == null) return;
        _current.ContextSummary = summary;
        _current.UpdatedAt = DateTime.UtcNow;
        await SaveAsync();
    }

    /// <summary>컨텍스트 압축 시 TaskState를 시스템 프롬프트에 주입할 텍스트 빌드.</summary>
    public string BuildCompactContextInjection()
    {
        if (_current == null) return string.Empty;
        var sb = new StringBuilder();
        sb.AppendLine("## 현재 작업 상태 (Working Memory)");
        if (!string.IsNullOrEmpty(_current.CurrentTask))
            sb.AppendLine($"현재 작업: {_current.CurrentTask}");
        if (!string.IsNullOrEmpty(_current.ContextSummary))
            sb.AppendLine($"이전 대화 요약: {_current.ContextSummary}");
        if (_current.ReferencedFiles.Count > 0)
            sb.AppendLine($"참조 파일: {string.Join(", ", _current.ReferencedFiles.TakeLast(10))}");
        if (_current.DecisionLog.Count > 0)
        {
            sb.AppendLine("최근 의사결정:");
            foreach (var d in _current.DecisionLog.TakeLast(3))
                sb.AppendLine($"  - {d.Decision} (이유: {d.Reason})");
        }
        return sb.ToString();
    }

    private async Task SaveAsync()
    {
        if (_current == null) return;
        var dir = Path.Combine(BaseDir, _current.SessionId);
        Directory.CreateDirectory(dir);
        var json = JsonSerializer.Serialize(_current, _json);
        await File.WriteAllTextAsync(GetPath(_current.SessionId), json);
    }

    private static string GetPath(string sessionId)
        => Path.Combine(BaseDir, sessionId, "task_state.json");
}
