<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Models\ReportJob;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Storage;

/**
 * Cron-команда удаления expired report-files.
 *
 * Идёт по `report_jobs` где `status='done' AND expires_at < NOW() AND
 * file_path IS NOT NULL`. Для каждой строки: удаляет файл из disk('local')
 * + UPDATE file_path=NULL.
 *
 * CTO-10: статус 'done' СОХРАНЯЕТСЯ; только file_path обнуляется. Это
 * позволяет UI показать «истёк» при отсутствии file_path. Сама запись
 * остаётся в истории.
 *
 * Failed jobs игнорируем — у них file_path обычно NULL, нечего чистить;
 * пользователь сам удалит через DELETE /api/reports/jobs/{id}.
 *
 * Запускается ежесуточно через Windows Task Scheduler / cron.
 *
 * --dry-run печатает плановые удаления без реальных операций.
 */
class ReportsCleanupExpired extends Command
{
    /** @var string */
    protected $signature = 'reports:cleanup-expired
        {--dry-run : Не удалять, только напечатать список плановых удалений}
        {--limit=1000 : Максимум jobs за один запуск}';

    /** @var string */
    protected $description = 'Удаление expired report-files (CTO-10): file_path=NULL, status="done" сохраняется';

    public function handle(): int
    {
        $dryRun = (bool) $this->option('dry-run');
        $limit = (int) $this->option('limit');

        $jobs = ReportJob::query()
            ->where('status', ReportJob::STATUS_DONE)
            ->whereNotNull('file_path')
            ->where('expires_at', '<', Carbon::now())
            ->orderBy('expires_at')
            ->limit($limit)
            ->get();

        if ($jobs->isEmpty()) {
            $this->info('Нет expired report-files для удаления.');

            return self::SUCCESS;
        }

        $count = 0;
        foreach ($jobs as $job) {
            $this->line(sprintf(
                '[%s] tenant=%d job=%d path=%s expired_at=%s',
                $dryRun ? 'DRY' : 'DEL',
                $job->tenant_id,
                $job->id,
                $job->file_path,
                $job->expires_at?->toIso8601String() ?? '?',
            ));

            if (! $dryRun) {
                Storage::disk('local')->delete($job->file_path);
                $job->update(['file_path' => null]);
            }
            $count++;
        }

        $this->info(sprintf(
            '%s %d файлов отчётов.',
            $dryRun ? 'Будет удалено:' : 'Удалено:',
            $count
        ));

        return self::SUCCESS;
    }
}
