<?php

namespace App\Services\Ticket;

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

final class BetProviderResolver
{
    /**
     * @param  array<int, mixed>|null  $providerCodes
     * @return list<array{code: string, name: string}>
     */
    public function resolve(?array $providerCodes): array
    {
        $usingImplicitDefault = $providerCodes === null || $providerCodes === [];
        $codes = $usingImplicitDefault ? [BetProvider::DEFAULT_CODE] : $providerCodes;

        $codes = array_values(array_unique(array_filter(array_map(
            static fn (mixed $code): string => strtoupper(trim((string) $code)),
            $codes,
        ))));

        if ($codes === []) {
            $codes = [BetProvider::DEFAULT_CODE];
            $usingImplicitDefault = true;
        }

        $providers = BetProvider::query()
            ->whereIn('code', $codes)
            ->where('is_enabled', true)
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get(['code', 'name'])
            ->keyBy('code');

        $missing = array_values(array_filter(
            $codes,
            static fn (string $code): bool => ! $providers->has($code),
        ));

        if (
            $missing === [BetProvider::DEFAULT_CODE]
            && $usingImplicitDefault
            && ! BetProvider::query()->exists()
        ) {
            return [[
                'code' => BetProvider::DEFAULT_CODE,
                'name' => 'Singapore',
            ]];
        }

        if ($missing !== []) {
            throw new TicketOperationException('bet_provider_unavailable', ErrorCode::ValidationFailed->value, 422, [
                'provider_codes' => $missing,
            ]);
        }

        return array_map(
            static fn (string $code): array => [
                'code' => $code,
                'name' => (string) $providers->get($code)?->name,
            ],
            $codes,
        );
    }
}
