<?php

namespace App\Jobs;

use App\Models\Employee;
use App\Models\ReportFile;
use App\Services\Payroll\ReportRenderer;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Throwable;

/**
 * Renders a large report PDF to storage off the request cycle. These reports
 * iterate thousands of per-member rows and take dompdf far longer than a web
 * request allows, so they are generated here and downloaded once READY.
 */
class GenerateReport implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    public int $timeout = 1200;

    public function __construct(public ReportFile $file) {}

    public function handle(ReportRenderer $renderer): void
    {
        // Large tables are memory-hungry in dompdf.
        ini_set('memory_limit', '1024M');

        $this->file->update(['status' => ReportFile::STATUS_PROCESSING, 'error' => null]);

        $ctx = [];
        if ($this->file->payroll_run_id) {
            $ctx['run'] = $this->file->run;
        }
        if ($this->file->employee_id) {
            $ctx['employee'] = $this->file->employee ?? Employee::findOrFail($this->file->employee_id);
        }
        if ($this->file->year) {
            $ctx['year'] = (int) $this->file->year;
        }

        $def = $renderer->resolve($this->file->key, $ctx);

        $pdf = Pdf::loadView($def['view'], $def['data'])->setPaper('a4', $def['orientation']);
        $bytes = $pdf->output();

        $path = "reports/{$this->file->id}-".$def['filename'];
        Storage::disk('local')->put($path, $bytes);

        $this->file->update([
            'status' => ReportFile::STATUS_READY,
            'path' => $path,
            'filename' => $def['filename'],
            'size' => strlen($bytes),
        ]);
    }

    public function failed(Throwable $e): void
    {
        $this->file->update([
            'status' => ReportFile::STATUS_FAILED,
            'error' => mb_substr($e->getMessage(), 0, 1000),
        ]);
    }
}
