namespace PSLauncher.Core.ReportTool;

/// <summary>
/// Déploie l'outil Report (page web hébergée dans XAMPP) depuis le sous-dossier
/// <c>_report/</c> bundled dans chaque ZIP PROSERVE vers le htdocs local.
/// Conserve N backups horodatés permettant un revert manuel via la UI Settings.
/// </summary>
public interface IReportToolDeployer
{
    /// <summary>
    /// Si <c>{installFolder}/_report/</c> existe, le copie vers
    /// <c>{HtdocsRoot}/{FolderName}/</c> via un rename atomique :
    /// <list type="number">
    ///   <item>copie récursive vers <c>{target}.new/</c></item>
    ///   <item>rename de l'existant vers <c>{target}.backup-{yyyyMMdd-HHmmss}/</c></item>
    ///   <item>rename <c>.new</c> → final</item>
    ///   <item>prune des vieux backups au-delà de <c>MaxBackups</c></item>
    /// </list>
    /// </summary>
    Task<DeployResult> DeployAsync(
        string installFolder,
        IProgress<DeployProgress>? progress,
        CancellationToken ct);

    /// <summary>
    /// Liste les backups horodatés disponibles dans <c>{HtdocsRoot}</c>, du plus
    /// récent au plus ancien. Vide si aucun backup ou si htdocs introuvable.
    /// </summary>
    Task<IReadOnlyList<BackupInfo>> ListBackupsAsync(CancellationToken ct);

    /// <summary>
    /// Revient à un backup horodaté précis. Swap atomique : la version actuelle
    /// est elle-même renommée en backup-{now} (donc le revert est lui-même
    /// reversible), puis le backup choisi est renommé en version active.
    /// </summary>
    Task<DeployResult> RevertAsync(string backupFolderName, CancellationToken ct);
}

public enum DeployStatus
{
    /// <summary>Le ZIP n'avait pas de sous-dossier <c>_report/</c>, rien à faire.</summary>
    SkippedNoSourceFolder,
    /// <summary>HtdocsRoot configuré n'existe pas (XAMPP pas installé là).</summary>
    XamppNotFound,
    /// <summary>Erreur I/O pendant la copie ou le rename.</summary>
    Failed,
    /// <summary>Déploiement (ou revert) réussi.</summary>
    Deployed,
    /// <summary>Revert demandé sur un backup qui n'existe pas / plus.</summary>
    BackupNotFound,
}

public sealed record DeployResult(
    DeployStatus Status,
    int FilesDeployed,
    long BytesDeployed,
    string TargetPath,
    string? ErrorMessage = null);

public sealed record DeployProgress(int FilesDone, int FilesTotal, string CurrentFilename);

/// <summary>
/// Métadonnées d'un backup horodaté présent dans <c>{HtdocsRoot}</c>.
/// </summary>
public sealed record BackupInfo(
    string FolderName,           // ProserveReport.backup-20260503-143022
    DateTime TimestampUtc,       // parsé depuis le suffixe du nom de dossier
    long SizeBytes);
