using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Hub;
using Microsoft.EntityFrameworkCore;

namespace ClaudeDo.Worker.Lifecycle;

/// <summary>
/// Startup-only sweep: warns when a list's working directory already contains a
/// <c>.claudedo-worktrees</c> folder inside its own tree — the symptom of the sibling-worktree
/// path bug (see <see cref="ClaudeDo.Worker.Git.WorktreeRootResolver"/>) from before it was
/// fixed. Detection only; moving or ignoring existing folders is left to the user.
/// </summary>
public sealed class LegacyWorktreeFolderRecovery : IHostedService
{
    public const string Phase = "legacy-worktrees";

    private const string LegacyFolderName = ".claudedo-worktrees";

    private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
    private readonly HubBroadcaster _broadcaster;
    private readonly ILogger<LegacyWorktreeFolderRecovery> _logger;

    public LegacyWorktreeFolderRecovery(
        IDbContextFactory<ClaudeDoDbContext> dbFactory,
        HubBroadcaster broadcaster,
        ILogger<LegacyWorktreeFolderRecovery> logger)
    {
        _dbFactory = dbFactory;
        _broadcaster = broadcaster;
        _logger = logger;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        await using var ctx = await _dbFactory.CreateDbContextAsync(cancellationToken);
        var lists = await new ListRepository(ctx).GetAllAsync(cancellationToken);

        var affected = FindAffectedListNames(lists);

        if (affected.Count > 0)
            _logger.LogWarning(
                "Legacy worktree folder recovery: found '{Folder}' inside the working tree of {Count} list(s): {Lists}. " +
                "This was previously caused by a trailing separator on the list's working directory; existing worktrees were not moved.",
                LegacyFolderName, affected.Count, string.Join(", ", affected));
        else
            _logger.LogInformation("Legacy worktree folder recovery: no lists affected");

        await _broadcaster.OperationProgress(OperationProgressOpKeys.StartupRecovery, Phase, lists.Count, lists.Count);
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

    /// <summary>Names of lists whose working dir already contains a <c>.claudedo-worktrees</c> folder.</summary>
    public static List<string> FindAffectedListNames(IEnumerable<ListEntity> lists) =>
        lists
            .Where(l => !string.IsNullOrWhiteSpace(l.WorkingDir))
            .Where(l => Directory.Exists(Path.Combine(l.WorkingDir!, LegacyFolderName)))
            .Select(l => l.Name)
            .ToList();
}
