<?php

declare(strict_types=1);

final class Asm3ContactPlanner
{
    public static function plan(string $path, PDO $db): array
    {
        $source = Asm3Analyzer::rows($path, ['owner', 'animal', 'adoption', 'animalvaccination']);
        $adopters = [];
        $depositors = [];
        $vets = [];
        foreach ($source['adoption'] ?? [] as $r) {
            if ((int) ($r['OWNERID'] ?? 0) > 0) {
                $adopters[(int) $r['OWNERID']] = true;
            }
        }
        foreach ($source['animal'] ?? [] as $r) {
            foreach (['BROUGHTINBYOWNERID', 'ORIGINALOWNERID'] as $field) {
                if ((int) ($r[$field] ?? 0) > 0) {
                    $depositors[(int) $r[$field]] = true;
                }
            }
            foreach (['CURRENTVETID', 'OWNERSVETID'] as $field) {
                if ((int) ($r[$field] ?? 0) > 0) {
                    $vets[(int) $r[$field]] = true;
                }
            }
        }
        foreach ($source['animalvaccination'] ?? [] as $r) {
            if ((int) ($r['ADMINISTERINGVETID'] ?? 0) > 0) {
                $vets[(int) $r['ADMINISTERINGVETID']] = true;
            }
        }
        $existing = $db
            ->query('SELECT id,kind,name,phone,email,city FROM directory_contacts WHERE deleted_at IS NULL')
            ->fetchAll(PDO::FETCH_ASSOC);
        $items = [];
        $summary = ['create' => 0, 'match' => 0, 'review' => 0];
        foreach ($source['owner'] ?? [] as $row) {
            $mapped = self::map(
                $row,
                isset($adopters[(int) $row['ID']]),
                isset($depositors[(int) $row['ID']]),
                isset($vets[(int) $row['ID']]),
            );
            $strong = [];
            $weak = [];
            $reasons = [];
            foreach ($existing as $contact) {
                $email = self::text($mapped['email']);
                $phone = self::phone($mapped['phone']);
                $sameEmail = $email !== '' && $email === self::text($contact['email']);
                $samePhone = $phone !== '' && $phone === self::phone($contact['phone']);
                $sameIdentity =
                    self::text($mapped['name']) === self::text($contact['name']) &&
                    self::text($mapped['city']) === self::text($contact['city']);
                if ($sameEmail || $samePhone || $sameIdentity) {
                    $strong[(int) $contact['id']] = $contact;
                    if ($sameEmail) {
                        $reasons[] = 'même adresse e-mail';
                    }
                    if ($samePhone) {
                        $reasons[] = 'même téléphone';
                    }
                    if ($sameIdentity) {
                        $reasons[] = 'même nom et ville';
                    }
                } elseif (
                    self::text($mapped['name']) !== '' &&
                    self::text($mapped['name']) === self::text($contact['name'])
                ) {
                    $weak[(int) $contact['id']] = $contact;
                }
            }
            if (count($strong) === 1) {
                $action = 'match';
                $candidates = $strong;
            } elseif (count($strong) > 1) {
                $action = 'review';
                $candidates = $strong;
            } elseif ($weak) {
                $action = 'review';
                $candidates = $weak;
                $reasons[] = 'même nom uniquement';
            } else {
                $action = 'create';
                $candidates = [];
            }
            $summary[$action]++;
            $items[] = [
                'asm3_id' => (int) $row['ID'],
                'action' => $action,
                'match_reasons' => array_values(array_unique($reasons)),
                'globinours_candidates' => array_values(
                    array_map(
                        static fn($c) => ['id' => (int) $c['id'], 'name' => $c['name'], 'city' => $c['city']],
                        $candidates,
                    ),
                ),
                'mapped' => $mapped,
            ];
        }
        return ['source' => basename($path), 'read_only' => true, 'summary' => $summary, 'items' => $items];
    }
    private static function map(array $r, bool $adopter, bool $depositor, bool $vetReferenced): array
    {
        $yes = static fn($v) => (string) $v === '1';
        $name = trim(
            (string) ($r['OWNERNAME'] ?? '' ?:
            trim((string) ($r['OWNERFORENAMES'] ?? '') . ' ' . (string) ($r['OWNERSURNAME'] ?? ''))),
        );
        $organization =
            (bool) preg_match('/\b(cabinet|clinique|cr[eé]matorium|association|refuge|fourri[eè]re)\b/iu', $name) ||
            $yes($r['ISSHELTER'] ?? 0) ||
            $yes($r['ISSUPPLIER'] ?? 0);
        $roles = [];
        if ($adopter || $yes($r['ISADOPTER'] ?? 0)) {
            $roles[] = 'adoptant';
        }
        if ($yes($r['ISFOSTERER'] ?? 0)) {
            $roles[] = 'fa';
        }
        if ($yes($r['ISVOLUNTEER'] ?? 0)) {
            $roles[] = 'benevole';
        }
        if ($depositor) {
            $roles[] = 'deposant';
        }
        if ($vetReferenced || $yes($r['ISVET'] ?? 0)) {
            $roles[] = $organization ? 'cabinet' : 'veterinaire';
        }
        if (preg_match('/cr[eé]matorium/iu', $name)) {
            $roles[] = 'crematorium';
        }
        $phones = array_values(
            array_filter([
                trim((string) ($r['MOBILETELEPHONE'] ?? '')),
                trim((string) ($r['HOMETELEPHONE'] ?? '')),
                trim((string) ($r['WORKTELEPHONE'] ?? '')),
            ]),
        );
        return [
            'kind' => $organization ? 'organization' : 'person',
            'name' => $name ?: 'Contact ASM3 ' . (int) $r['ID'],
            'phone' => $phones[0] ?? null,
            'email' => trim((string) ($r['EMAILADDRESS'] ?? '')) ?: null,
            'address' => trim((string) ($r['OWNERADDRESS'] ?? '')) ?: null,
            'postal_code' => trim((string) ($r['OWNERPOSTCODE'] ?? '')) ?: null,
            'city' => trim((string) ($r['OWNERTOWN'] ?? '')) ?: null,
            'country' => trim((string) ($r['OWNERCOUNTRY'] ?? '')) ?: 'France',
            'notes' => trim((string) ($r['COMMENTS'] ?? '')) ?: null,
            'roles' => array_values(array_unique($roles)),
        ];
    }
    private static function text(mixed $v): string
    {
        return mb_strtolower(trim((string) $v));
    }
    private static function phone(mixed $v): string
    {
        return (string) preg_replace('/\D+/', '', (string) $v);
    }
}
