namespace PSLauncher.Core.Migrations;

/// <summary>
/// Applique les scripts SQL livrés dans le sous-répertoire <c>_migrations/</c>
/// d'un build PROSERVE installé. Chaque script tournant en transaction, le
/// résultat est tracké dans une table <c>_launcher_migrations</c> pour qu'un
/// même script ne soit pas rejoué deux fois (mêmes garanties que Flyway/Doctrine).
/// </summary>
public interface IDatabaseMigrationService
{
    /// <summary>
    /// Cherche <c>{installFolder}/_migrations/*.sql</c>, applique en ordre alphabétique
    /// les scripts pas encore présents dans <c>_launcher_migrations</c>, et reporte la
    /// progression. Retourne la liste détaillée des opérations (appliquées + skippées).
    /// </summary>
    Task<MigrationResult> ApplyMigrationsAsync(
        string installFolder,
        IProgress<MigrationProgress>? progress,
        CancellationToken ct);

    /// <summary>
    /// Liste les migrations déjà appliquées en base. Utile pour la vue Settings.
    /// </summary>
    Task<IReadOnlyList<AppliedMigration>> ListAppliedAsync(CancellationToken ct);

    /// <summary>
    /// Test de connexion. Retourne null si OK, sinon le message d'erreur formaté.
    /// </summary>
    Task<string?> TestConnectionAsync(CancellationToken ct);
}

public sealed record MigrationProgress(int Done, int Total, string CurrentFilename);

public sealed record MigrationResult(
    IReadOnlyList<MigrationOutcome> Outcomes,
    bool AllSucceeded,
    string? FailureMessage)
{
    public int AppliedCount => Outcomes.Count(o => o.Status == MigrationStatus.Applied);
    public int SkippedCount => Outcomes.Count(o => o.Status == MigrationStatus.Skipped);
    public int FailedCount  => Outcomes.Count(o => o.Status == MigrationStatus.Failed);
    public bool HasNoMigrationsFolder => !Outcomes.Any() && AllSucceeded;
}

public sealed record MigrationOutcome(
    string Filename,
    MigrationStatus Status,
    long DurationMs,
    string? Error);

public enum MigrationStatus { Skipped, Applied, Failed }

public sealed record AppliedMigration(
    string Filename,
    DateTime AppliedAt,
    string Checksum,
    long DurationMs);
