<?php

declare(strict_types=1);

final class Asm3AnimalImporter
{
    public static function run(string $path, PDO $db, bool $apply = false, bool $createBackup = true): array
    {
        $plan = Asm3MigrationPlanner::plan($path, $db);
        $hash = hash_file('sha256', $path);
        if ($hash === false) {
            throw new RuntimeException(t('asm3.hash_failed'));
        }
        $result = [
            'mode' => $apply ? 'apply' : 'dry-run',
            'source' => basename($path),
            'source_sha256' => $hash,
            'planned' => $plan['summary'],
            'created' => 0,
            'linked_matches' => 0,
            'skipped_existing_import' => 0,
            'skipped_match' => 0,
            'skipped_review' => $plan['summary']['review'],
            'backup' => null,
            'read_only' => !$apply,
        ];
        if (!$apply) {
            $result['would_create'] = $plan['summary']['create'];
            return $result;
        }
        if ($createBackup) {
            $backup = BackupService::create('pre-asm3-import');
            $result['backup'] = $backup['name'] ?? null;
        }
        $ownsTransaction = !$db->inTransaction();
        if ($ownsTransaction) {
            $db->beginTransaction();
        }
        try {
            $run = $db->prepare(
                "INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(:name,:hash,'completed','{}',:backup)",
            );
            $run->execute([':name' => basename($path), ':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='animal' AND source_id=:source",
                );
                $check->execute([':hash' => $hash, ':source' => $item['asm3_id']]);
                if ($check->fetchColumn()) {
                    $result['skipped_existing_import']++;
                    continue;
                }
                if ($item['action'] === 'match') {
                    $target = (int) ($item['globinours_candidates'][0]['id'] ?? 0);
                    if ($target <= 0) {
                        $result['skipped_match']++;
                        continue;
                    }
                    $result['linked_matches']++;
                } else {
                    $target = self::insert($db, $item['mapped'], $item['asm3_id']);
                    $result['created']++;
                }
                $db->prepare(
                    "INSERT INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(:hash,'animal',: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;
    }

    private static function insert(PDO $db, array $a, int $sourceId): int
    {
        $code = trim((string) $a['internal_code']);
        if ($code === '') {
            $code = 'ASM3-' . $sourceId;
        }
        $exists = $db->prepare('SELECT 1 FROM animals WHERE internal_code=:code');
        $exists->execute([':code' => $code]);
        if ($exists->fetchColumn()) {
            $code .= '-ASM3-' . $sourceId;
        }
        $stmt = $db->prepare(
            "INSERT INTO animals(internal_code,name,species,sex,birth_date,birth_is_estimated,chip_id,status,sterilized,sterilization_status,sterilization_date,color,breed,notes,intake_date,archived_at,identification_type,identification_date,identification_registration_status,adoption_availability,adoption_available_from,adoption_unavailability_reason,compatibility_dogs,compatibility_cats,compatibility_children,house_trained,created_at,updated_at) VALUES(:code,:name,:species,:sex,:birth,:estimated,:chip,:status,:sterilized,:sterilization_status,:sterilization_date,:color,:breed,:notes,:intake,:archived,:identification_type,:identification_date,:registration,:availability,:available_from,:unavailable_reason,:dogs,:cats,:children,:trained,datetime('now'),datetime('now'))",
        );
        $stmt->execute([
            ':code' => $code,
            ':name' => $a['name'] ?: 'Animal ASM3 ' . $sourceId,
            ':species' => $a['species'] ?: 'inconnu',
            ':sex' => $a['sex'],
            ':birth' => $a['birth_date'],
            ':estimated' => $a['birth_is_estimated'],
            ':chip' => $a['chip_id'] ?: null,
            ':status' => $a['status'],
            ':sterilized' => $a['sterilization_status'] === 'yes' ? 1 : 0,
            ':sterilization_status' => $a['sterilization_status'],
            ':sterilization_date' => $a['sterilization_date'],
            ':color' => $a['color'],
            ':breed' => $a['breed'] ?: null,
            ':notes' => $a['notes'] ?: null,
            ':intake' => $a['intake_date'],
            ':archived' => $a['archived'] ? date('Y-m-d H:i:s') : null,
            ':identification_type' => $a['identification_type'],
            ':identification_date' => $a['identification_date'],
            ':registration' => $a['identification_registration_status'],
            ':availability' => $a['adoption_availability'],
            ':available_from' => $a['adoption_available_from'],
            ':unavailable_reason' => $a['adoption_unavailability_reason'] ?: null,
            ':dogs' => $a['compatibility_dogs'],
            ':cats' => $a['compatibility_cats'],
            ':children' => $a['compatibility_children'],
            ':trained' => $a['house_trained'],
        ]);
        $id = (int) $db->lastInsertId();
        if ($a['deceased_date']) {
            $db->prepare(
                "INSERT INTO animal_deaths(animal_id,deceased_date,cause_code,cause_details,place_type,body_disposition,notes) VALUES(:animal,:date,'unknown',NULL,'inconnu','pending',:notes)",
            )->execute([':animal' => $id, ':date' => $a['deceased_date'], ':notes' => 'Importé depuis ASM3']);
        }
        return $id;
    }
}
