<?php

declare(strict_types=1);

namespace BotGuard\Services\Export;

use BotGuard\Core\Response;

/**
 * Streams rows to a CSV download.
 *
 * Values are written via fputcsv (proper quoting/escaping) and a leading
 * apostrophe is added to values that could be interpreted as a spreadsheet
 * formula, mitigating CSV-injection when the file is opened in Excel.
 */
final class CsvExporter
{
    /**
     * @param string[]                       $headers
     * @param array<int, array<int|string, mixed>> $rows
     */
    public function download(string $filename, array $headers, array $rows): Response
    {
        $handle = fopen('php://temp', 'r+');
        fputcsv($handle, $headers);

        foreach ($rows as $row) {
            fputcsv($handle, array_map([$this, 'sanitize'], array_values($row)));
        }

        rewind($handle);
        $body = (string) stream_get_contents($handle);
        fclose($handle);

        return (new Response($body))
            ->withHeader('Content-Type', 'text/csv; charset=utf-8')
            ->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
            ->withHeader('Cache-Control', 'no-store');
    }

    private function sanitize(mixed $value): string
    {
        $value = (string) $value;

        // Neutralise spreadsheet formula injection.
        if ($value !== '' && in_array($value[0], ['=', '+', '-', '@'], true)) {
            return "'" . $value;
        }

        return $value;
    }
}
