<?php

declare(strict_types=1);

namespace App\Services\Supplier;

use Illuminate\Support\Facades\Log;

/**
 * Streaming-парсер CSV-экспорта `/admin/report/index?type=49` поставщика.
 *
 * Spec: docs/superpowers/specs/2026-05-11-plan4-billing-csv-admin-design.md §5.2
 * Ожидаемые столбцы: vid;project;tag;phone;phones;time (placeholder; уточнится
 * после Plan 3 Tasks 1-2 discovery с credentials поставщика).
 *
 * Возвращает Generator — вызывающий (CsvReconcileJob) сам решает, сколько
 * копить в памяти. BOM + CRLF поддерживаются. Malformed rows skip + log.
 */
final class SupplierCsvParser
{
    private const EXPECTED_COLUMNS = 6;

    /**
     * @return iterable<int, array{vid: string, project: string, phone: string, time: int}>
     */
    public function parse(string $rawCsv): iterable
    {
        if ($rawCsv === '') {
            return;
        }

        // Убираем BOM (UTF-8 BOM = EF BB BF)
        if (str_starts_with($rawCsv, "\xEF\xBB\xBF")) {
            $rawCsv = substr($rawCsv, 3);
        }

        // Нормализуем CRLF → LF
        $rawCsv = str_replace("\r\n", "\n", $rawCsv);

        $lines = explode("\n", $rawCsv);
        $headerSkipped = false;
        $lineNo = 0;

        foreach ($lines as $line) {
            $lineNo++;
            if ($line === '') {
                continue;
            }
            if (! $headerSkipped) {
                $headerSkipped = true;

                continue;
            }

            $cols = str_getcsv($line, separator: ';');
            if (count($cols) < self::EXPECTED_COLUMNS) {
                Log::warning('supplier_csv_parser.malformed_row', [
                    'line_no' => $lineNo,
                    'columns_found' => count($cols),
                    'expected' => self::EXPECTED_COLUMNS,
                    'sample' => substr($line, 0, 100),
                ]);

                continue;
            }

            yield [
                'vid' => (string) $cols[0],
                'project' => (string) $cols[1],
                'phone' => (string) $cols[3],
                'time' => (int) $cols[5],
            ];
        }
    }
}
