<?php

declare(strict_types=1);

namespace App\Exports;

use App\Services\ReportService;
use App\Support\Reports\ReportDefinition;
use Illuminate\Database\Eloquent\Builder;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;

/**
 * The one Excel export every report shares.
 *
 * Rather than one export class per report — twenty-two files that would
 * each just repeat "run the report's query, use its columns as headings, use
 * its row mapper" — this class takes a report key and reads that shape from
 * {@see ReportService} at export time. `map()` calls the exact same row
 * closure the HTML viewer uses, so a spreadsheet column can never quietly
 * drift from what the on-screen table shows for the same report.
 */
class ReportExport implements FromQuery, ShouldAutoSize, WithHeadings, WithMapping
{
    private readonly ReportDefinition $definition;

    /**
     * @param  array<string, mixed>  $filters
     */
    public function __construct(
        private readonly ReportService $reports,
        private readonly string $key,
        private readonly array $filters = [],
    ) {
        /** @var ReportDefinition $definition */
        $definition = $this->reports->definition($this->key);
        $this->definition = $definition;
    }

    public function query(): Builder
    {
        return $this->reports->run($this->key, $this->filters);
    }

    /**
     * @return array<int, string>
     */
    public function headings(): array
    {
        return array_map(fn ($column) => $column->label, $this->definition->columns);
    }

    /**
     * @return array<int, mixed>
     */
    public function map($record): array
    {
        $row = ($this->definition->row)($record);

        return array_map(fn ($column) => $row[$column->key] ?? null, $this->definition->columns);
    }
}
