namespace AxCopilot.Services;

/// <summary>
/// 라인 기반 텍스트 diff 서비스. 두 텍스트의 변경 사항을 비교합니다.
/// </summary>
public static class DiffService
{
    public enum DiffType { Equal, Added, Removed }

    public record DiffLine(DiffType Type, int? OldLineNo, int? NewLineNo, string Content);

    /// <summary>두 텍스트를 라인 단위로 비교하여 diff 결과를 반환합니다.</summary>
    public static List<DiffLine> ComputeDiff(string oldText, string newText)
    {
        var oldLines = (oldText ?? "").Split('\n');
        var newLines = (newText ?? "").Split('\n');
        var result = new List<DiffLine>();

        // LCS (Longest Common Subsequence) 기반 간단 diff
        var lcs = ComputeLcs(oldLines, newLines);
        int oi = 0, ni = 0, li = 0;

        while (oi < oldLines.Length || ni < newLines.Length)
        {
            if (li < lcs.Count && oi < oldLines.Length && ni < newLines.Length &&
                oldLines[oi].TrimEnd('\r') == lcs[li] && newLines[ni].TrimEnd('\r') == lcs[li])
            {
                result.Add(new DiffLine(DiffType.Equal, oi + 1, ni + 1, oldLines[oi].TrimEnd('\r')));
                oi++; ni++; li++;
            }
            else if (li < lcs.Count && oi < oldLines.Length &&
                     oldLines[oi].TrimEnd('\r') != lcs[li])
            {
                result.Add(new DiffLine(DiffType.Removed, oi + 1, null, oldLines[oi].TrimEnd('\r')));
                oi++;
            }
            else if (ni < newLines.Length &&
                     (li >= lcs.Count || newLines[ni].TrimEnd('\r') != lcs[li]))
            {
                result.Add(new DiffLine(DiffType.Added, null, ni + 1, newLines[ni].TrimEnd('\r')));
                ni++;
            }
            else
            {
                // 나머지 처리
                if (oi < oldLines.Length)
                {
                    result.Add(new DiffLine(DiffType.Removed, oi + 1, null, oldLines[oi].TrimEnd('\r')));
                    oi++;
                }
                if (ni < newLines.Length)
                {
                    result.Add(new DiffLine(DiffType.Added, null, ni + 1, newLines[ni].TrimEnd('\r')));
                    ni++;
                }
            }
        }

        return result;
    }

    private static List<string> ComputeLcs(string[] a, string[] b)
    {
        int m = a.Length, n = b.Length;
        var dp = new int[m + 1, n + 1];

        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++)
                dp[i, j] = a[i - 1].TrimEnd('\r') == b[j - 1].TrimEnd('\r')
                    ? dp[i - 1, j - 1] + 1
                    : Math.Max(dp[i - 1, j], dp[i, j - 1]);

        // 역추적
        var lcs = new List<string>();
        int x = m, y = n;
        while (x > 0 && y > 0)
        {
            if (a[x - 1].TrimEnd('\r') == b[y - 1].TrimEnd('\r'))
            {
                lcs.Add(a[x - 1].TrimEnd('\r'));
                x--; y--;
            }
            else if (dp[x - 1, y] > dp[x, y - 1])
                x--;
            else
                y--;
        }
        lcs.Reverse();
        return lcs;
    }

    /// <summary>diff 결과를 통계 요약 문자열로 반환합니다.</summary>
    public static string GetSummary(List<DiffLine> diff)
    {
        int added = diff.Count(d => d.Type == DiffType.Added);
        int removed = diff.Count(d => d.Type == DiffType.Removed);
        return $"+{added} -{removed} 라인 변경";
    }
}
