using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using Microsoft.EntityFrameworkCore;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Data.Tests;

public sealed class TaskAttachmentRepositoryTests : IDisposable
{
    private readonly string _dbPath;
    private readonly ClaudeDoDbContext _ctx;
    private readonly TaskAttachmentRepository _repo;

    private const string ListId = "l1";
    private const string TaskId = "t1";

    public TaskAttachmentRepositoryTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_att_{Guid.NewGuid():N}.db");
        var options = new DbContextOptionsBuilder<ClaudeDoDbContext>()
            .UseSqlite($"Data Source={_dbPath}")
            .Options;
        _ctx = new ClaudeDoDbContext(options);
        _ctx.Database.EnsureCreated();
        _repo = new TaskAttachmentRepository(_ctx);

        _ctx.Lists.Add(new ListEntity { Id = ListId, Name = "Test", CreatedAt = DateTime.UtcNow });
        _ctx.Tasks.Add(new TaskEntity { Id = TaskId, ListId = ListId, Title = "T", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow });
        _ctx.SaveChanges();
    }

    public void Dispose()
    {
        _ctx.Dispose();
        foreach (var suffix in new[] { "", "-wal", "-shm" })
            try { File.Delete(_dbPath + suffix); } catch { }
    }

    private TaskAttachmentEntity MakeAttachment(string fileName) => new()
    {
        Id = Guid.NewGuid().ToString(),
        TaskId = TaskId,
        FileName = fileName,
        ByteSize = 100,
        CreatedAt = DateTime.UtcNow,
    };

    [Fact]
    public async Task Add_ListByTaskId_Delete_roundtrip()
    {
        var a1 = MakeAttachment("file1.txt");
        var a2 = MakeAttachment("file2.txt");

        await _repo.AddAsync(a1);
        await _repo.AddAsync(a2);

        var list = await _repo.ListByTaskIdAsync(TaskId);
        Assert.Equal(2, list.Count);
        Assert.Contains(list, a => a.FileName == "file1.txt");
        Assert.Contains(list, a => a.FileName == "file2.txt");

        await _repo.DeleteAsync(TaskId, "file1.txt");

        var afterDelete = await _repo.ListByTaskIdAsync(TaskId);
        Assert.Single(afterDelete);
        Assert.Equal("file2.txt", afterDelete[0].FileName);
    }

    [Fact]
    public async Task GetAsync_returns_correct_entity()
    {
        var a = MakeAttachment("target.txt");
        await _repo.AddAsync(a);

        var found = await _repo.GetAsync(TaskId, "target.txt");

        Assert.NotNull(found);
        Assert.Equal(a.Id, found!.Id);
    }

    [Fact]
    public async Task GetAsync_returns_null_when_missing()
    {
        var result = await _repo.GetAsync(TaskId, "nope.txt");
        Assert.Null(result);
    }

    [Fact]
    public async Task ListByTaskId_ordered_by_created_at()
    {
        var base_ = DateTime.UtcNow;
        var a1 = new TaskAttachmentEntity { Id = Guid.NewGuid().ToString(), TaskId = TaskId, FileName = "first.txt", ByteSize = 1, CreatedAt = base_ };
        var a2 = new TaskAttachmentEntity { Id = Guid.NewGuid().ToString(), TaskId = TaskId, FileName = "second.txt", ByteSize = 1, CreatedAt = base_.AddSeconds(1) };

        await _repo.AddAsync(a2);
        await _repo.AddAsync(a1);

        var list = await _repo.ListByTaskIdAsync(TaskId);
        Assert.Equal("first.txt", list[0].FileName);
        Assert.Equal("second.txt", list[1].FileName);
    }
}
