<?php

declare(strict_types=1);
final class Asm3LitterImporter
{
    public static function run(string $path, PDO $db, bool $apply = false, bool $createBackup = true): array
    {
        $hash = hash_file('sha256', $path);
        $src = Asm3Analyzer::rows($path, ['animallitter', 'animal']);
        $links = [];
        $q = $db->prepare(
            "SELECT source_id,target_id FROM asm3_import_links WHERE source_sha256=:h AND entity_type='animal'",
        );
        $q->execute([':h' => $hash]);
        foreach ($q as $r) {
            $links[(int) $r['source_id']] = (int) $r['target_id'];
        }
        $animals = [];
        foreach ($src['animal'] ?? [] as $a) {
            $animals[(string) $a['ACCEPTANCENUMBER']][] = (int) $a['ID'];
        }
        $result = [
            'mode' => $apply ? 'apply' : 'dry-run',
            'read_only' => !$apply,
            'litters' => count($src['animallitter'] ?? []),
            'would_import' => 0,
            'unresolved' => 0,
            'created' => 0,
            'kittens_linked' => 0,
            'backup' => null,
        ];
        foreach ($src['animallitter'] ?? [] as $l) {
            $parent = (int) $l['PARENTANIMALID'];
            $kids = array_filter($animals[(string) $l['ACCEPTANCENUMBER']] ?? [], fn($id) => $id !== $parent);
            if (!isset($links[$parent]) || array_filter($kids, fn($id) => !isset($links[$id]))) {
                $result['unresolved']++;
                continue;
            }
            $result['would_import']++;
        }
        if (!$apply) {
            return $result;
        }
        if ($createBackup) {
            $b = BackupService::create('pre-asm3-import');
            $result['backup'] = $b['name'] ?? null;
        }
        $owns = !$db->inTransaction();
        if ($owns) {
            $db->beginTransaction();
        }
        try {
            $db->prepare(
                "INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(:n,:h,'completed','{}',:b)",
            )->execute([':n' => basename($path) . ' · portées', ':h' => $hash, ':b' => $result['backup']]);
            $run = (int) $db->lastInsertId();
            foreach ($src['animallitter'] ?? [] as $l) {
                $source = (int) $l['ID'];
                $seen = $db->prepare(
                    "SELECT 1 FROM asm3_import_links WHERE source_sha256=:h AND entity_type='litter' AND source_id=:s",
                );
                $seen->execute([':h' => $hash, ':s' => $source]);
                if ($seen->fetchColumn()) {
                    continue;
                }
                $parent = (int) $l['PARENTANIMALID'];
                $kids = array_values(
                    array_filter($animals[(string) $l['ACCEPTANCENUMBER']] ?? [], fn($id) => $id !== $parent),
                );
                if (!isset($links[$parent]) || array_filter($kids, fn($id) => !isset($links[$id]))) {
                    continue;
                }
                $db->prepare('INSERT INTO litters(mother_id,birth_date,notes) VALUES(:parent,:date,:notes)')->execute([
                    ':parent' => $links[$parent],
                    ':date' => substr((string) $l['DATE'], 0, 10),
                    ':notes' => trim((string) $l['COMMENTS']) ?: null,
                ]);
                $target = (int) $db->lastInsertId();
                $ins = $db->prepare(
                    'INSERT OR IGNORE INTO litter_kittens(litter_id,animal_id,position) VALUES(:litter,:animal,:position)',
                );
                foreach ($kids as $i => $kid) {
                    $ins->execute([':litter' => $target, ':animal' => $links[$kid], ':position' => $i + 1]);
                    $result['kittens_linked']++;
                }
                $db->prepare(
                    "INSERT INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(:h,'litter',:s,:t,:r)",
                )->execute([':h' => $hash, ':s' => $source, ':t' => $target, ':r' => $run]);
                $result['created']++;
            }
            if ($owns) {
                $db->commit();
            }
        } catch (Throwable $e) {
            if ($owns && $db->inTransaction()) {
                $db->rollBack();
            }
            throw $e;
        }
        return $result;
    }
}
