<?php

namespace App\Ocr;

/**
 * Corrections OCR pour plaques françaises (AA-123-AA) et VIN (17 caractères).
 * Port fidèle de lib/ocr-parser.ts.
 */
final class OcrParser
{
    /** Sur les positions LETTRE : chiffres ambigus → lettres. */
    private const PLATE_LETTER_CORRECTIONS = [
        '0' => 'O', '1' => 'I', '2' => 'Z', '5' => 'S', '8' => 'B',
    ];

    /** Sur les positions CHIFFRE : lettres ambiguës → chiffres. */
    private const PLATE_DIGIT_CORRECTIONS = [
        'O' => '0', 'I' => '1', 'Z' => '2', 'S' => '5', 'B' => '8',
    ];

    /** VIN : 17 caractères, ne contient jamais I, O, Q. */
    private const VIN_CORRECTIONS = [
        'O' => '0', 'I' => '1', 'Q' => '0',
    ];

    private const PLATE_VALID = '/^[A-Z]{2}-\d{3}-[A-Z]{2}$/';
    private const VIN_VALID = '/^[A-HJ-NPR-Z0-9]{17}$/';

    public function parsePlate(string $raw): OcrParseResult
    {
        if ('' === trim($raw) || 'UNREADABLE' === strtoupper(trim($raw))) {
            return new OcrParseResult(null, $raw, 'low');
        }

        $upper = strtoupper(trim($raw));
        $stripped = preg_replace('/[^A-Z0-9-]/', '', $upper) ?? '';
        $alphanum = str_replace('-', '', $stripped);

        if (strlen($alphanum) < 7) {
            return new OcrParseResult(null, $raw, 'low');
        }

        $chars = str_split(substr($alphanum, 0, 7));
        $letterPositions = [0, 1, 5, 6];
        $digitPositions = [2, 3, 4];

        $corrected = [];
        foreach ($chars as $i => $c) {
            if (in_array($i, $letterPositions, true)) {
                $corrected[$i] = self::PLATE_LETTER_CORRECTIONS[$c] ?? $c;
            } elseif (in_array($i, $digitPositions, true)) {
                $corrected[$i] = self::PLATE_DIGIT_CORRECTIONS[$c] ?? $c;
            } else {
                $corrected[$i] = $c;
            }
        }

        $formatted = sprintf(
            '%s%s-%s%s%s-%s%s',
            $corrected[0], $corrected[1], $corrected[2], $corrected[3], $corrected[4], $corrected[5], $corrected[6]
        );

        $isValid = 1 === preg_match(self::PLATE_VALID, $formatted);

        return new OcrParseResult($formatted, $raw, $isValid ? 'high' : 'low');
    }

    public function parseVin(string $raw): OcrParseResult
    {
        if ('' === trim($raw) || 'UNREADABLE' === strtoupper(trim($raw))) {
            return new OcrParseResult(null, $raw, 'low');
        }

        $upper = strtoupper(trim($raw));
        $stripped = preg_replace('/[^A-Z0-9]/', '', $upper) ?? '';

        $corrected = strtr($stripped, self::VIN_CORRECTIONS);

        if (17 !== strlen($corrected)) {
            if (strlen($corrected) > 17) {
                $sub = substr($corrected, 0, 17);
                $isValid = 1 === preg_match(self::VIN_VALID, $sub);

                return new OcrParseResult($sub, $raw, $isValid ? 'high' : 'low');
            }

            return new OcrParseResult($corrected !== '' ? $corrected : null, $raw, 'low');
        }

        $isValid = 1 === preg_match(self::VIN_VALID, $corrected);

        return new OcrParseResult($corrected, $raw, $isValid ? 'high' : 'low');
    }
}
