namespace ClaudeDo.Ui.ViewModels.Modals;

/// Shared unified-diff parser used by both the per-task diff viewer and the
/// combined (planning) diff viewer so they render identically.
public static class UnifiedDiffParser
{
    public static List<DiffFileViewModel> Parse(string? raw)
    {
        var files = new List<DiffFileViewModel>();
        if (string.IsNullOrWhiteSpace(raw)) return files;

        DiffFileViewModel? current = null;
        int oldLine = 0, newLine = 0;

        foreach (var line in raw.Split('\n'))
        {
            if (line.StartsWith("diff --git ", StringComparison.Ordinal))
            {
                // e.g. "diff --git a/src/Foo.cs b/src/Foo.cs"
                var parts = line.Split(' ');
                var path = parts.Length >= 4 ? parts[3][2..] : line;
                current = new DiffFileViewModel { Path = path };
                files.Add(current);
                oldLine = 0; newLine = 0;
                continue;
            }

            if (current == null) continue;

            // File-level metadata that carries the change kind.
            if (line.StartsWith("new file", StringComparison.Ordinal))
            {
                current.Status = DiffFileStatus.Added;
                continue;
            }
            if (line.StartsWith("deleted file", StringComparison.Ordinal))
            {
                current.Status = DiffFileStatus.Deleted;
                continue;
            }
            if (line.StartsWith("rename from ", StringComparison.Ordinal))
            {
                current.Status = DiffFileStatus.Renamed;
                current.OldPath = line["rename from ".Length..];
                continue;
            }
            if (line.StartsWith("rename to ", StringComparison.Ordinal))
            {
                current.Status = DiffFileStatus.Renamed;
                current.Path = line["rename to ".Length..];
                continue;
            }
            if (line.StartsWith("Binary files", StringComparison.Ordinal) ||
                line.StartsWith("GIT binary patch", StringComparison.Ordinal))
            {
                current.IsBinary = true;
                continue;
            }

            if (line.StartsWith("@@ ", StringComparison.Ordinal))
            {
                // e.g. "@@ -10,7 +10,9 @@"
                ParseHunkHeader(line, out oldLine, out newLine);
                continue;
            }

            // Skip remaining diff metadata lines
            if (line.StartsWith("--- ", StringComparison.Ordinal) ||
                line.StartsWith("+++ ", StringComparison.Ordinal) ||
                line.StartsWith("index ", StringComparison.Ordinal) ||
                line.StartsWith("old mode", StringComparison.Ordinal) ||
                line.StartsWith("new mode", StringComparison.Ordinal) ||
                line.StartsWith("similarity index", StringComparison.Ordinal) ||
                line.StartsWith("copy from", StringComparison.Ordinal) ||
                line.StartsWith("copy to", StringComparison.Ordinal))
                continue;

            if (line.StartsWith('+'))
            {
                current.Lines.Add(new DiffLineViewModel
                {
                    Kind = DiffLineKind.Add,
                    NewNo = newLine++,
                    Text = line.Length > 1 ? line[1..] : "",
                });
                current.Additions++;
            }
            else if (line.StartsWith('-'))
            {
                current.Lines.Add(new DiffLineViewModel
                {
                    Kind = DiffLineKind.Del,
                    OldNo = oldLine++,
                    Text = line.Length > 1 ? line[1..] : "",
                });
                current.Deletions++;
            }
            else if (line.StartsWith(' '))
            {
                current.Lines.Add(new DiffLineViewModel
                {
                    Kind = DiffLineKind.Ctx,
                    OldNo = oldLine++,
                    NewNo = newLine++,
                    Text = line.Length > 1 ? line[1..] : "",
                });
            }
        }

        return files;
    }

    /// Flattens multiple parsed files into a single line stream, inserting a
    /// file-header row before each file so boundaries are visible in a
    /// single-pane (combined) view.
    public static List<DiffLineViewModel> Flatten(IEnumerable<DiffFileViewModel> files)
    {
        var lines = new List<DiffLineViewModel>();
        foreach (var file in files)
        {
            lines.Add(new DiffLineViewModel { Kind = DiffLineKind.File, Text = file.Path });
            foreach (var line in file.Lines)
                lines.Add(line);
        }
        return lines;
    }

    private static void ParseHunkHeader(string header, out int oldStart, out int newStart)
    {
        oldStart = 1; newStart = 1;
        // Format: @@ -<old>,<count> +<new>,<count> @@
        var at = header.IndexOf("@@", 3, StringComparison.Ordinal);
        var inner = at > 0 ? header[3..at].Trim() : header;
        var segs = inner.Split(' ');
        foreach (var seg in segs)
        {
            if (seg.StartsWith('-') && int.TryParse(seg[1..].Split(',')[0], out var o))
                oldStart = o;
            else if (seg.StartsWith('+') && int.TryParse(seg[1..].Split(',')[0], out var n))
                newStart = n;
        }
    }
}
