<?php

namespace App\Actions\Communications;

use App\Models\Communication\SolicitorPhoneNumber;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use RuntimeException;

class ResolveCalledNumberAction
{
    public function handle(string $toNumber): SolicitorPhoneNumber
    {
        $normalized = $this->normalizePhoneNumber($toNumber);

        // Try exact normalized match first.
        $phoneNumber = SolicitorPhoneNumber::query()
            ->with(['solicitor', 'type'])
            ->where('normalized_phone_number', $normalized)
            ->where('is_active', true)
            ->first();

        // Fall back to a raw string match in case the stored value is not
        // in E.164 format (e.g. stored as 07xxx rather than +447xxx).
        if (! $phoneNumber) {
            $phoneNumber = SolicitorPhoneNumber::query()
                ->with(['solicitor', 'type'])
                ->whereIn('normalized_phone_number', $this->phoneCandidates($toNumber, $normalized))
                ->where('is_active', true)
                ->first();
        }

        if (! $phoneNumber) {
            Log::warning('ResolveCalledNumberAction: no active solicitor phone number matched.', [
                'to_raw'        => $toNumber,
                'to_normalized' => $normalized,
                'candidates'    => $this->phoneCandidates($toNumber, $normalized),
            ]);
            throw new RuntimeException("No active solicitor phone number found for [{$normalized}] (raw: [{$toNumber}]).");
        }

        return $phoneNumber;
    }

    /**
     * Return all plausible representations of the number so the DB lookup is
     * resilient to minor formatting differences.
     *
     * @return array<int, string>
     */
    protected function phoneCandidates(string $raw, string $normalized): array
    {
        $raw = trim($raw);
        $digitsOnly = preg_replace('/\D+/', '', $normalized) ?? '';

        $candidates = array_filter([
            $raw,
            $normalized,
            $digitsOnly,
            str_starts_with($normalized, '+44') ? '0' . substr($normalized, 3) : null,
            str_starts_with($digitsOnly, '44')  ? '0' . substr($digitsOnly,  2) : null,
        ]);

        return array_values(array_unique($candidates));
    }

    protected function normalizePhoneNumber(?string $value): string
    {
        $value = trim((string) $value);

        if ($value === '') {
            throw new RuntimeException('Phone number cannot be empty.');
        }

        $value = preg_replace('/[^\d+]/', '', $value) ?? '';

        if (Str::startsWith($value, '00')) {
            $value = '+' . substr($value, 2);
        }

        if (! Str::startsWith($value, '+')) {
            if (Str::startsWith($value, '0')) {
                $value = '+44' . substr($value, 1);
            } else {
                $value = '+' . $value;
            }
        }

        return $value;
    }
}