using ClaudeDo.Data.Models;
using Microsoft.EntityFrameworkCore;

namespace ClaudeDo.Data.Repositories;

public sealed class ListRepository
{
    private readonly ClaudeDoDbContext _context;

    public ListRepository(ClaudeDoDbContext context) => _context = context;

    public async Task AddAsync(ListEntity entity, CancellationToken ct = default)
    {
        _context.Lists.Add(entity);
        await _context.SaveChangesAsync(ct);
    }

    public async Task UpdateAsync(ListEntity entity, CancellationToken ct = default)
    {
        _context.Lists.Update(entity);
        await _context.SaveChangesAsync(ct);
    }

    public async Task DeleteAsync(string listId, CancellationToken ct = default)
    {
        await _context.Lists.Where(l => l.Id == listId).ExecuteDeleteAsync(ct);
    }

    public async Task<ListEntity?> GetByIdAsync(string listId, CancellationToken ct = default)
    {
        return await _context.Lists.FirstOrDefaultAsync(l => l.Id == listId, ct);
    }

    public async Task<List<ListEntity>> GetAllAsync(CancellationToken ct = default)
    {
        return await _context.Lists.OrderBy(l => l.CreatedAt).ToListAsync(ct);
    }

    public async Task<List<TagEntity>> GetTagsAsync(string listId, CancellationToken ct = default)
    {
        return await _context.Lists
            .Where(l => l.Id == listId)
            .SelectMany(l => l.Tags)
            .ToListAsync(ct);
    }

    public async Task AddTagAsync(string listId, long tagId, CancellationToken ct = default)
    {
        var list = await _context.Lists.Include(l => l.Tags).FirstOrDefaultAsync(l => l.Id == listId, ct);
        if (list is null) return;
        var tag = await _context.Tags.FindAsync([tagId], ct);
        if (tag is not null && !list.Tags.Any(t => t.Id == tagId))
        {
            list.Tags.Add(tag);
            await _context.SaveChangesAsync(ct);
        }
    }

    public async Task RemoveTagAsync(string listId, long tagId, CancellationToken ct = default)
    {
        var list = await _context.Lists.Include(l => l.Tags).FirstOrDefaultAsync(l => l.Id == listId, ct);
        if (list is null) return;
        var tag = list.Tags.FirstOrDefault(t => t.Id == tagId);
        if (tag is not null)
        {
            list.Tags.Remove(tag);
            await _context.SaveChangesAsync(ct);
        }
    }

    public async Task<ListConfigEntity?> GetConfigAsync(string listId, CancellationToken ct = default)
    {
        return await _context.ListConfigs.FirstOrDefaultAsync(c => c.ListId == listId, ct);
    }

    public async Task SetConfigAsync(ListConfigEntity config, CancellationToken ct = default)
    {
        var existing = await _context.ListConfigs.FirstOrDefaultAsync(c => c.ListId == config.ListId, ct);
        if (existing is null)
        {
            _context.ListConfigs.Add(config);
        }
        else
        {
            existing.Model = config.Model;
            existing.SystemPrompt = config.SystemPrompt;
            existing.AgentPath = config.AgentPath;
        }
        await _context.SaveChangesAsync(ct);
    }

    public async Task<bool> DeleteConfigAsync(string listId, CancellationToken ct = default)
    {
        var affected = await _context.ListConfigs
            .Where(c => c.ListId == listId)
            .ExecuteDeleteAsync(ct);
        return affected > 0;
    }
}
