using ClaudeDo.Worker.Report;

namespace ClaudeDo.Worker.Tests.Report;

public class ClaudeHistoryReaderTests : IDisposable
{
    private readonly string _root;
    public ClaudeHistoryReaderTests()
    {
        _root = Path.Combine(Path.GetTempPath(), $"cdh_{Guid.NewGuid():N}");
        Directory.CreateDirectory(_root);
    }
    public void Dispose() { try { Directory.Delete(_root, true); } catch { } }

    private void WriteSession(string projectDir, string file, params string[] lines)
    {
        var dir = Path.Combine(_root, projectDir);
        Directory.CreateDirectory(dir);
        File.WriteAllLines(Path.Combine(dir, file), lines);
    }

    private static string UserLine(string cwd, string ts, string text) =>
        $$$"""{"type":"user","cwd":{{{Json(cwd)}}},"timestamp":"{{{ts}}}","message":{"role":"user","content":[{"type":"text","text":{{{Json(text)}}}}]}}""";

    private static string AssistantLine(string cwd, string ts, string text) =>
        $$$"""{"type":"assistant","cwd":{{{Json(cwd)}}},"timestamp":"{{{ts}}}","message":{"role":"assistant","content":[{"type":"text","text":{{{Json(text)}}}}]}}""";

    private static string Json(string s) => System.Text.Json.JsonSerializer.Serialize(s);

    [Fact]
    public async Task SessionSpanningTwoRepos_KeepsLastSummaryPerRepo()
    {
        WriteSession("proj", "s.jsonl",
            AssistantLine(@"C:\Dev\Repos\A", "2026-06-01T08:00:00Z", "summary A"),
            AssistantLine(@"C:\Dev\Repos\B", "2026-06-01T09:00:00Z", "summary B"));

        var reader = new ClaudeHistoryReader(_root);
        var result = await reader.ReadAsync(new DateOnly(2026, 6, 1), new DateOnly(2026, 6, 3),
            Array.Empty<string>());

        Assert.Equal(2, result.Count);
        Assert.Equal(new[] { "summary A" }, result.Single(r => r.RepoPath.EndsWith("A")).Days.Single().Summaries);
        Assert.Equal(new[] { "summary B" }, result.Single(r => r.RepoPath.EndsWith("B")).Days.Single().Summaries);
    }

    [Fact]
    public async Task Extracts_Prompts_And_Last_Assistant_Summary_GroupedByRepoAndDay()
    {
        WriteSession("proj", "s1.jsonl",
            UserLine(@"C:\Dev\Repos\App", "2026-06-01T08:00:00Z", "Add login"),
            AssistantLine(@"C:\Dev\Repos\App", "2026-06-01T08:05:00Z", "first summary"),
            AssistantLine(@"C:\Dev\Repos\App", "2026-06-01T08:30:00Z", "final summary"));

        var reader = new ClaudeHistoryReader(_root);
        var result = await reader.ReadAsync(new DateOnly(2026, 6, 1), new DateOnly(2026, 6, 3),
            Array.Empty<string>());

        var repo = Assert.Single(result);
        Assert.Equal(@"C:\Dev\Repos\App", repo.RepoPath);
        var day = Assert.Single(repo.Days);
        Assert.Equal(new[] { "Add login" }, day.Prompts);
        Assert.Equal(new[] { "final summary" }, day.Summaries);
    }

    [Fact]
    public async Task Drops_Sessions_Under_Excluded_Prefix_CaseInsensitive()
    {
        WriteSession("priv", "s.jsonl",
            UserLine(@"C:\Private\Secret", "2026-06-01T08:00:00Z", "private work"));

        var reader = new ClaudeHistoryReader(_root);
        var result = await reader.ReadAsync(new DateOnly(2026, 6, 1), new DateOnly(2026, 6, 3),
            new[] { @"c:\private" });

        Assert.Empty(result);
    }

    [Fact]
    public async Task Filters_By_Date_Window_And_Skips_Noise_And_Malformed()
    {
        WriteSession("proj", "s.jsonl",
            "this is not json",
            UserLine(@"C:\Dev\App", "2026-05-01T08:00:00Z", "too old"),
            UserLine(@"C:\Dev\App", "2026-06-02T08:00:00Z", "in range"),
            UserLine(@"C:\Dev\App", "2026-06-02T09:00:00Z", "noise <system-reminder> blah"));

        var reader = new ClaudeHistoryReader(_root);
        var result = await reader.ReadAsync(new DateOnly(2026, 6, 1), new DateOnly(2026, 6, 3),
            Array.Empty<string>());

        var day = Assert.Single(Assert.Single(result).Days);
        Assert.Equal(new[] { "in range" }, day.Prompts);
    }
}
