using System.IO;
using System.Text;
using AxCopilot.ViewModels;

namespace AxCopilot.Services.Agent;

/// <summary>
/// Phase 17-G: AgentLoopService — 멀티파일 Diff 추적기.
/// · 쓰기 도구 실행 전 원본 파일 내용 캡처
/// · 성공 후 변경 내용을 MultiFileDiffViewModel에 기록
/// · 도구 위험도 LOW/MED/HIGH 분류 지원 (ToolRiskMapper 연계)
/// </summary>
public partial class AgentLoopService
{
    // 멀티파일 Diff ViewModel — ChatWindow가 바인딩
    private MultiFileDiffViewModel? _diffViewModel;

    /// <summary>멀티파일 Diff ViewModel. ChatWindow UI에 바인딩하여 Diff 패널을 표시합니다.</summary>
    public MultiFileDiffViewModel DiffViewModel
        => _diffViewModel ??= new MultiFileDiffViewModel();

    // Diff 추적 대상 쓰기 도구 (내용 기반 비교 가능한 텍스트 파일 생성/수정 도구)
    private static readonly HashSet<string> _diffWriteTools = new(StringComparer.OrdinalIgnoreCase)
    {
        "file_write", "file_edit", "script_create",
        "html_create", "markdown_create", "csv_create",
    };

    // ─────────────────────────────────────────────────────────────────────
    //  파일 경로 추출 + 원본 내용 캡처
    // ─────────────────────────────────────────────────────────────────────

    /// <summary>
    /// 도구 입력 JSON에서 파일 경로를 추출합니다.
    /// "path" → "file_path" 순으로 탐색합니다.
    /// </summary>
    internal static string? ExtractFilePathFromInput(System.Text.Json.JsonElement? input)
    {
        if (input == null) return null;
        if (input.Value.TryGetProperty("path",      out var p))  return p.GetString();
        if (input.Value.TryGetProperty("file_path", out var fp)) return fp.GetString();
        return null;
    }

    /// <summary>
    /// 쓰기 도구 실행 전 원본 파일 내용을 캡처합니다.
    /// 파일이 없으면 빈 문자열 반환 (신규 생성 케이스).
    /// </summary>
    internal static string CaptureOriginalFileContent(string? filePath)
    {
        if (string.IsNullOrWhiteSpace(filePath)) return "";
        try
        {
            return File.Exists(filePath)
                ? File.ReadAllText(filePath, Encoding.UTF8)
                : ""; // 신규 파일 — 원본 없음
        }
        catch { return ""; }
    }

    // ─────────────────────────────────────────────────────────────────────
    //  Diff 기록
    // ─────────────────────────────────────────────────────────────────────

    /// <summary>
    /// 쓰기 도구 성공 후 파일 변경을 DiffViewModel에 기록합니다.
    /// 변경 후 내용은 디스크에서 재읽기 (도구가 이미 파일에 기록 완료).
    /// UI 스레드 Dispatcher를 통해 안전하게 ViewModel 업데이트.
    /// </summary>
    internal void TrackFileModificationForDiff(string toolName, string? filePath, string originalContent)
    {
        if (string.IsNullOrWhiteSpace(filePath)) return;
        if (!_diffWriteTools.Contains(toolName)) return;
        if (!_settings.Settings.Llm.EnableDiffTracker) return;

        try
        {
            // 도구가 파일을 기록한 후의 내용(신규 내용) 읽기
            var newContent = File.Exists(filePath)
                ? File.ReadAllText(filePath, Encoding.UTF8)
                : originalContent; // 파일이 사라진 경우

            if (originalContent == newContent) return; // 내용 변화 없음

            var vm = DiffViewModel;
            if (Dispatcher != null)
                Dispatcher(() => vm.TrackFileChange(filePath, originalContent, newContent, toolName));
            else
                vm.TrackFileChange(filePath, originalContent, newContent, toolName);

            // 이벤트 로그
            _ = _eventLog?.AppendAsync(AgentEventLogType.ToolResult,
                System.Text.Json.JsonSerializer.Serialize(new
                {
                    type       = "diff_tracked",
                    toolName,
                    filePath,
                    addedLines = newContent.Split('\n').Length - originalContent.Split('\n').Length,
                    riskLevel  = ToolRiskMapper.GetRisk(toolName).ToString(),
                }));
        }
        catch (Exception ex)
        {
            LogService.Warn($"[DiffTracker] 파일 변경 추적 실패: {ex.Message}");
        }
    }

    /// <summary>
    /// 새 에이전트 세션 시작 시 Diff 목록을 초기화합니다.
    /// ChatWindow에서 이전 세션의 Diff 항목이 남지 않도록 합니다.
    /// </summary>
    internal void ResetDiffTracker()
    {
        if (_diffViewModel == null) return;
        if (Dispatcher != null)
            Dispatcher(() => _diffViewModel.Clear());
        else
            _diffViewModel.Clear();
    }
}
