<?php

declare(strict_types=1);

namespace App\Domain\Backup\Listeners;

use App\Domain\Audit\Services\AuditWriter;
use App\Domain\Backup\Enums\BackupStatus;
use App\Domain\Backup\Events\BackupCreated;
use App\Domain\Backup\Models\Backup;
use App\Domain\Sysapi\Contracts\SysapiBridge;
use App\Domain\Sysapi\Exceptions\SysapiException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Throwable;

/**
 * BackupCreated event'i dinler — hesabın keep-count limitini aşan eski yedekleri siler.
 *
 * Akış:
 *   1. Yeni yedek tamamlandığında dispatch edilen BackupCreated event'i tetikler.
 *   2. Listener queue'ya düşer (kullanıcı response'u beklemez).
 *   3. Hesabın keep_count'undan fazla yedek varsa en eskilerini sysapi('backup-prune')
 *      ile diskten siler ve DB satırını soft-delete eder.
 *
 * Retention parametreleri config/onoxsoft.php → backup.daily_retention_days,
 * keep_count config'ten alınmazsa default 5'tir.
 */
final class BackupRetentionListener implements ShouldQueue
{
    public function __construct(private readonly SysapiBridge $sysapi) {}

    public function handle(BackupCreated $event): void
    {
        $backup = $event->backup;
        $account = $backup->account;

        if (! $account) {
            return;
        }

        $keepCount = (int) config('onoxsoft.backup.keep_count_per_account', 5);

        // En eski → en yeni sırada keep_count'tan fazlasını al
        $excess = Backup::where('account_id', $account->id)
            ->where('status', BackupStatus::Completed)
            ->whereNull('deleted_at')
            ->orderByDesc('created_at')
            ->skip($keepCount)
            ->take(50) // bir seferde fazla pruning yapma
            ->get();

        foreach ($excess as $old) {
            try {
                if ($old->file_path) {
                    $result = $this->sysapi->run('backup-prune', [
                        'backup_id' => $old->id,
                        'backup_file' => $old->file_path,
                    ]);

                    if ($result->failed()) {
                        // Disk silme başarısızsa DB satırı kalsın, sysadmin bakar
                        AuditWriter::write(
                            action: 'backup.retention_prune_failed',
                            target: $old,
                            metadata: $result->toAuditLog(),
                            outcome: 'failure',
                            errorMessage: $result->stderr,
                        );

                        continue;
                    }
                }

                AuditWriter::write(
                    action: 'backup.retention_pruned',
                    target: $old,
                    metadata: [
                        'reason' => 'keep_count_exceeded',
                        'keep_count' => $keepCount,
                        'triggered_by_backup_id' => $backup->id,
                    ],
                    outcome: 'success',
                );

                $old->delete();
            } catch (SysapiException|Throwable $e) {
                AuditWriter::write(
                    action: 'backup.retention_prune_failed',
                    target: $old,
                    metadata: ['error' => $e->getMessage()],
                    outcome: 'failure',
                    errorMessage: $e->getMessage(),
                );
            }
        }
    }
}
