<?php

namespace App\Services\Reporting;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Writer\Csv;

/**
 * Every report method above returns a plain array; this service converts
 * ANY such array (or an explicit ['headers' => [...], 'rows' => [...]]
 * shape) into PDF, Excel, or CSV — adding a new export format only means
 * adding one method here, never touching report-generation logic (see
 * 05-saas-architecture.md §8).
 */
class ReportExportService
{
    /**
     * Normalizes arbitrary nested report data into a flat headers+rows
     * table. For simple list-of-associative-arrays data this is a direct
     * mapping; for grouped/nested report shapes (e.g. AdminReportingService::agencies())
     * the caller should pass the specific sub-array that's tabular.
     */
    private function normalize(array $data): array
    {
        if (isset($data['headers'], $data['rows'])) {
            return $data;
        }

        if (empty($data)) {
            return ['headers' => [], 'rows' => []];
        }

        $headers = array_keys((array) reset($data));
        $rows = array_map(fn ($row) => array_values((array) $row), $data);

        return ['headers' => $headers, 'rows' => $rows];
    }

    public function toCsv(array $data, string $filename): string
    {
        if (! class_exists(\PhpOffice\PhpSpreadsheet\Spreadsheet::class)) {
            throw new \RuntimeException(
                'CSV export requires the phpoffice/phpspreadsheet package, which is not installed in this deployment. ' .
                'If you have Composer access, run: composer require phpoffice/phpspreadsheet'
            );
        }
        $table = $this->normalize($data);
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $sheet->fromArray($table['headers'], null, 'A1');
        $sheet->fromArray($table['rows'], null, 'A2');

        $path = $this->outputPath($filename, 'csv');
        (new Csv($spreadsheet))->save($path);

        return $path;
    }

    public function toExcel(array $data, string $filename, string $title = 'Report'): string
    {
        if (! class_exists(\PhpOffice\PhpSpreadsheet\Spreadsheet::class)) {
            throw new \RuntimeException(
                'Excel export requires the phpoffice/phpspreadsheet package, which is not installed in this deployment. ' .
                'If you have Composer access, run: composer require phpoffice/phpspreadsheet'
            );
        }
        $table = $this->normalize($data);
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle(substr($title, 0, 31));

        $sheet->fromArray($table['headers'], null, 'A1');
        foreach ($table['headers'] as $i => $header) {
            $sheet->getStyleByColumnAndRow($i + 1, 1)->getFont()->setBold(true);
        }
        $sheet->fromArray($table['rows'], null, 'A2');

        foreach (range('A', $sheet->getHighestColumn()) as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }

        $path = $this->outputPath($filename, 'xlsx');
        (new Xlsx($spreadsheet))->save($path);

        return $path;
    }

    public function toPdf(array $data, string $filename, string $title = 'Report'): string
    {
        if (! class_exists(\Dompdf\Dompdf::class)) {
            throw new \RuntimeException(
                'PDF export requires the dompdf/dompdf package, which is not installed in this deployment. ' .
                'If you have Composer access, run: composer require dompdf/dompdf'
            );
        }
        $table = $this->normalize($data);
        $html = view('reporting/export_pdf', ['title' => $title, 'headers' => $table['headers'], 'rows' => $table['rows']]);

        $dompdf = new \Dompdf\Dompdf();
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'landscape');
        $dompdf->render();

        $path = $this->outputPath($filename, 'pdf');
        file_put_contents($path, $dompdf->output());

        return $path;
    }

    private function outputPath(string $filename, string $extension): string
    {
        $dir = WRITEPATH . 'uploads/reports';
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        return "{$dir}/{$filename}.{$extension}";
    }
}
