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

namespace ClaudeDo.Worker.Tickets;

public sealed record TicketImportResult(int Examined, int Created);

/// <summary>
/// Holt das Board des verknüpften Ticket-Projekts und legt für jedes offene, dem Token-Inhaber
/// zugewiesene Ticket einen Idle-Task an. Bereits importierte Tickets werden übersprungen und
/// NICHT aktualisiert — ein erneuter Import würde sonst Titel/Beschreibung überschreiben und
/// damit die am Task gemachten Notizen zerstören.
/// </summary>
public sealed class TicketImportService
{
    private const int StatusOffen = 1;

    private readonly TicketClientFactory _clients;
    private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
    private readonly ILogger<TicketImportService> _logger;

    public TicketImportService(
        TicketClientFactory clients,
        IDbContextFactory<ClaudeDoDbContext> dbFactory,
        ILogger<TicketImportService> logger)
    {
        _clients = clients;
        _dbFactory = dbFactory;
        _logger = logger;
    }

    public async Task<TicketImportResult> ImportAsync(string listId, CancellationToken ct)
    {
        var client = _clients.Create()
            ?? throw new TicketApiException("Ticketsystem ist nicht eingerichtet (Base-URL oder Token fehlt).");

        await using var ctx = await _dbFactory.CreateDbContextAsync(ct);

        var config = await ctx.ListConfigs.AsNoTracking()
            .FirstOrDefaultAsync(c => c.ListId == listId, ct);
        var projectId = config?.TicketProjectId
            ?? throw new TicketApiException("Diese Liste ist mit keinem Ticket-Projekt verknüpft.");

        var identity = await client.GetIdentityAsync(ct);
        var board = await client.GetProjectBoardAsync(projectId, ct);

        var mine = board
            .Where(t => t.StatusId == StatusOffen)
            .Where(t => string.Equals(t.AssigneeName, identity.UserName, StringComparison.OrdinalIgnoreCase))
            .ToList();

        var known = await ctx.Tasks.AsNoTracking()
            .Where(t => t.ListId == listId && t.TicketRef != null)
            .Select(t => t.TicketRef!)
            .ToListAsync(ct);
        var knownSet = known.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var repo = new TaskRepository(ctx);
        var created = 0;

        foreach (var ticket in mine)
        {
            var reference = $"bandel:{ticket.Id}";
            if (!knownSet.Add(reference)) continue;

            await repo.AddAsync(new TaskEntity
            {
                Id = Guid.NewGuid().ToString(),
                ListId = listId,
                Title = ticket.Title,
                Description = BuildDescription(ticket),
                Status = TaskStatus.Idle,
                CreatedAt = DateTime.UtcNow,
                TicketRef = reference,
                CreatedBy = "ticketsystem",
            }, ct);
            created++;
        }

        _logger.LogInformation(
            "Ticket-Import für Liste {list_id}: {examined} geprüft, {created} neue Tasks",
            listId, board.Count, created);

        return new TicketImportResult(board.Count, created);
    }

    private static string BuildDescription(TicketBoardItem ticket)
    {
        var body = string.IsNullOrWhiteSpace(ticket.Description) ? "" : ticket.Description.Trim() + "\n\n";
        return body + $"Ticket #{ticket.Id}";
    }
}
