namespace JobTrackerApi.Services
{
    public sealed class DatabaseBackupHostedService : BackgroundService
    {
        private readonly IDatabaseBackupRunner _runner;
        private readonly ILogger<DatabaseBackupHostedService> _logger;
        private readonly IConfiguration _cfg;
        private readonly IStartupReadiness _startupReadiness;

        public DatabaseBackupHostedService(
            IDatabaseBackupRunner runner,
            ILogger<DatabaseBackupHostedService> logger,
            IConfiguration cfg,
            IStartupReadiness startupReadiness)
        {
            _runner = runner;
            _logger = logger;
            _cfg = cfg;
            _startupReadiness = startupReadiness;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await _startupReadiness.WaitUntilReadyAsync(stoppingToken);

            if (!_cfg.GetValue("Backups:Enabled", true))
            {
                _logger.LogInformation("Automated database backups disabled (Backups:Enabled=false).");
                return;
            }

            if (!_runner.IsSupported)
            {
                _logger.LogWarning("Automated database backups are unavailable for the configured provider. Configure external backups for MySQL/MariaDB.");
                return;
            }

            var hour = _cfg.GetValue("Backups:HourLocal", 3);
            if (hour < 0 || hour > 23) hour = 3;

            // Catch-up: guarantee at least one recent backup exists even if the
            // process never stays up long enough to reach the scheduled hour.
            var latest = _runner.GetLatestBackupUtc();
            if (latest is null || latest < DateTime.UtcNow.AddHours(-24))
            {
                await TryBackupAsync(stoppingToken);
            }

            while (!stoppingToken.IsCancellationRequested)
            {
                var now = DateTime.Now;
                var next = new DateTime(now.Year, now.Month, now.Day, hour, 0, 0);
                if (next <= now) next = next.AddDays(1);

                _logger.LogInformation("Next database backup scheduled at {Next}.", next);
                try
                {
                    await Task.Delay(next - now, stoppingToken);
                }
                catch (TaskCanceledException)
                {
                    break;
                }

                await TryBackupAsync(stoppingToken);
            }
        }

        private async Task TryBackupAsync(CancellationToken ct)
        {
            try
            {
                await _runner.RunOnceAsync(ct);
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Database backup failed.");
            }
        }
    }
}
