<?php

declare(strict_types=1);

final class Asm3ContactImporter
{
    public static function run(string $path, PDO $db, bool $apply = false, bool $createBackup = true): array
    {
        $plan = Asm3ContactPlanner::plan($path, $db);
        $hash = hash_file('sha256', $path);
        if ($hash === false) {
            throw new RuntimeException(t('asm3.hash_unavailable'));
        }
        $result = [
            'mode' => $apply ? 'apply' : 'dry-run',
            'entity' => 'contacts',
            'planned' => $plan['summary'],
            'created' => 0,
            'linked_matches' => 0,
            'skipped_match' => 0,
            'skipped_review' => $plan['summary']['review'],
            'backup' => null,
            'read_only' => !$apply,
            'would_create' => $plan['summary']['create'],
        ];
        if (!$apply) {
            return $result;
        }
        if ($createBackup) {
            $backup = BackupService::create('pre-asm3-import');
            $result['backup'] = $backup['name'] ?? null;
        }
        $ownsTransaction = !$db->inTransaction();
        if ($ownsTransaction) {
            $db->beginTransaction();
        }
        try {
            $db->prepare(
                "INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(:name,:hash,'completed','{}',:backup)",
            )->execute([':name' => basename($path) . ' · contacts', ':hash' => $hash, ':backup' => $result['backup']]);
            $runId = (int) $db->lastInsertId();
            foreach ($plan['items'] as $item) {
                if ($item['action'] === 'review') {
                    continue;
                }
                $check = $db->prepare(
                    "SELECT target_id FROM asm3_import_links WHERE source_sha256=:hash AND entity_type='contact' AND source_id=:source",
                );
                $check->execute([':hash' => $hash, ':source' => $item['asm3_id']]);
                if ($check->fetchColumn()) {
                    continue;
                }
                $c = $item['mapped'];
                if ($item['action'] === 'match') {
                    $target = (int) ($item['globinours_candidates'][0]['id'] ?? 0);
                    if ($target <= 0) {
                        $result['skipped_match']++;
                        continue;
                    }
                    $result['linked_matches']++;
                } else {
                    $db->prepare(
                        'INSERT INTO directory_contacts(kind,name,phone,email,address,postal_code,city,country,notes) VALUES(:kind,:name,:phone,:email,:address,:postal,:city,:country,:notes)',
                    )->execute([
                        ':kind' => $c['kind'],
                        ':name' => $c['name'],
                        ':phone' => $c['phone'],
                        ':email' => $c['email'],
                        ':address' => $c['address'],
                        ':postal' => $c['postal_code'],
                        ':city' => $c['city'],
                        ':country' => $c['country'],
                        ':notes' => $c['notes'],
                    ]);
                    $target = (int) $db->lastInsertId();
                    $result['created']++;
                }
                $role = $db->prepare(
                    'INSERT OR IGNORE INTO directory_contact_roles(contact_id,role) VALUES(:contact,:role)',
                );
                foreach ($c['roles'] as $value) {
                    $role->execute([':contact' => $target, ':role' => $value]);
                }
                $db->prepare(
                    "INSERT INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(:hash,'contact',:source,:target,:run)",
                )->execute([':hash' => $hash, ':source' => $item['asm3_id'], ':target' => $target, ':run' => $runId]);
            }
            $db->prepare('UPDATE asm3_import_runs SET summary_json=:summary WHERE id=:id')->execute([
                ':summary' => json_encode($result, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR),
                ':id' => $runId,
            ]);
            if ($ownsTransaction) {
                $db->commit();
            }
        } catch (Throwable $e) {
            if ($ownsTransaction && $db->inTransaction()) {
                $db->rollBack();
            }
            throw $e;
        }
        return $result;
    }
}
