<?php

namespace App\Domain\Participant\Services;

use App\Domain\Identity\Models\Person;
use Illuminate\Support\Collection;

class DuplicateDetectionService
{
    /**
     * Find potential duplicates for a new registration.
     * Returns a collection of possible matches with confidence scores.
     */
    public function findPotentialDuplicates(string $name, ?string $phone = null, ?string $email = null, ?string $dateOfBirth = null): Collection
    {
        $matches = collect();

        // Exact phone match (highest confidence)
        if ($phone) {
            $normalized = $this->normalizePhone($phone);
            // Both phone spellings in one group. Eloquent does wrap the wheres
            // a global scope adds in their own group, so the academy and branch
            // scopes are not escaping through this OR today — but the grouping
            // is one hand-written `->where()` away from mattering, and the same
            // shape has already been fixed once in GuardianResolver.
            $phoneMatches = Person::where(function ($q) use ($normalized, $phone) {
                $q->where('phone', $normalized)->orWhere('phone', $phone);
            })
                ->with('participant')
                ->get();
            foreach ($phoneMatches as $person) {
                $matches->push([
                    'person' => $person,
                    'confidence' => 95,
                    'match_reason' => 'phone_exact',
                ]);
            }
        }

        // Exact email match
        if ($email) {
            $emailMatches = Person::where('email', strtolower($email))
                ->with('participant')
                ->get()
                ->filter(fn ($p) => !$matches->contains(fn ($m) => $m['person']->id === $p->id));
            foreach ($emailMatches as $person) {
                $matches->push([
                    'person' => $person,
                    'confidence' => 90,
                    'match_reason' => 'email_exact',
                ]);
            }
        }

        // Name similarity match
        if ($name) {
            $nameMatches = Person::where(function ($q) use ($name) {
                $q->where('name_ar', 'ilike', "%{$name}%")
                  ->orWhere('name', 'ilike', "%{$name}%");
            })->with('participant')
              ->limit(10)
              ->get()
              ->filter(fn ($p) => !$matches->contains(fn ($m) => $m['person']->id === $p->id));

            foreach ($nameMatches as $person) {
                $confidence = 60;
                // Boost confidence if DOB also matches
                if ($dateOfBirth && $person->date_of_birth?->format('Y-m-d') === $dateOfBirth) {
                    $confidence = 85;
                }
                $matches->push([
                    'person' => $person,
                    'confidence' => $confidence,
                    'match_reason' => $confidence >= 85 ? 'name_and_dob' : 'name_similar',
                ]);
            }
        }

        return $matches->sortByDesc('confidence')->values();
    }

    private function normalizePhone(string $phone): string
    {
        $phone = preg_replace('/[\s\-\(\)]/', '', $phone);
        if (str_starts_with($phone, '0')) {
            $phone = '+20' . substr($phone, 1);
        }
        if (!str_starts_with($phone, '+')) {
            $phone = '+20' . $phone;
        }
        return $phone;
    }
}
