<?php

namespace App\Services\Ticket;

use App\Lottery\ErrorCode;
use App\Exceptions\TicketOperationException;

final class NumberNormalizer
{
    public function normalize(string $playCode, string $number, ?string $dimension = null): string
    {
        $trimmed = strtoupper(str_replace(' ', '', trim($number)));

        return match ($playCode) {
            'roll' => $this->normalizeRoll($trimmed),
            default => $this->normalizeDigits($playCode, $trimmed, $dimension),
        };
    }

    private function normalizeRoll(string $value): string
    {
        if (! preg_match('/^[0-9R]{4}$/', $value)) {
            throw new TicketOperationException('invalid_roll_number', ErrorCode::BetInvalidNumber->value);
        }

        if (! str_contains($value, 'R')) {
            throw new TicketOperationException('roll_requires_r', ErrorCode::BetInvalidPlayInput->value);
        }

        return $value;
    }

    private function normalizeDigits(string $playCode, string $value, ?string $dimension = null): string
    {
        if (! preg_match('/^[0-9]+$/', $value)) {
            throw new TicketOperationException('invalid_number', ErrorCode::BetInvalidNumber->value);
        }

        $length = strlen($value);
        $expected = match ($playCode) {
            'big', 'small', 'pos_4a', 'pos_4b', 'pos_4c', 'pos_4d', 'pos_4e', 'straight', 'box', 'ibox', 'mbox' => 4,
            'pos_3a', 'pos_3b', 'pos_3c', 'pos_3abc' => 3,
            'pos_2a', 'pos_2b', 'pos_2c', 'pos_2abc' => 2,
            'head', 'tail', 'odd', 'even', 'digit_big', 'digit_small' => match ($dimension) {
                'D2' => 1,
                'D3' => 1,
                'D4', null => 1,
                default => 1,
            },
            default => null,
        };

        if ($expected !== null && $length !== $expected) {
            throw new TicketOperationException('invalid_number_length', ErrorCode::BetInvalidNumber->value);
        }

        return $value;
    }
}
