<?php

declare(strict_types=1);

function parseDatabaseUrl(string $url): array
{
    $parts = parse_url($url);
    if ($parts === false) {
        throw new RuntimeException('Invalid database URL.');
    }

    $host = $parts['host'] ?? 'localhost';
    $port = isset($parts['port']) ? (int) $parts['port'] : 5432;
    $user = $parts['user'] ?? '';
    $pass = $parts['pass'] ?? '';
    $db = ltrim($parts['path'] ?? '', '/');

    return [
        'dsn' => sprintf('pgsql:host=%s;port=%d;dbname=%s', $host, $port, $db),
        'user' => $user,
        'pass' => $pass,
    ];
}

function connect(string $url): PDO
{
    $config = parseDatabaseUrl($url);
    $pdo = new PDO($config['dsn'], $config['user'], $config['pass'], [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);

    return $pdo;
}

$sourceUrl = getenv('SOURCE_DATABASE_URL') ?: '';
$targetUrl = getenv('TARGET_DATABASE_URL') ?: '';

if ($sourceUrl === '' || $targetUrl === '') {
    fwrite(STDERR, "Usage: SOURCE_DATABASE_URL=... TARGET_DATABASE_URL=... php scripts/validate-migration.php\n");
    exit(1);
}

$tables = [
    'sites',
    'type_machines',
    'machines',
    'model_types',
    'composants',
    'pieces',
    'products',
    'constructeurs',
    'documents',
    'custom_fields',
    'custom_field_values',
    'machine_component_links',
    'machine_piece_links',
    'machine_product_links',
    'type_machine_component_requirements',
    'type_machine_piece_requirements',
    'type_machine_product_requirements',
    '_machineconstructeurs',
    '_composantconstructeurs',
    '_piececonstructeurs',
    '_productconstructeurs',
    'profiles',
];

$skipTables = array_filter(array_map('trim', explode(',', getenv('SKIP_TABLES') ?: 'profiles')));

$sourceTableMap = [
    'model_types' => ['ModelType', 'model_types'],
    '_machineconstructeurs' => ['_MachineConstructeurs', '_machineconstructeurs'],
    '_composantconstructeurs' => ['_ComposantConstructeurs', '_composantconstructeurs'],
    '_piececonstructeurs' => ['_PieceConstructeurs', '_piececonstructeurs'],
    '_productconstructeurs' => ['_ProductConstructeurs', '_productconstructeurs'],
];

function resolveTable(PDO $db, array $candidates): ?string
{
    foreach ($candidates as $candidate) {
        $exists = (bool) $db
            ->query(sprintf("SELECT to_regclass('public.%s')", $candidate))
            ->fetchColumn();
        if ($exists) {
            return $candidate;
        }

        $quoted = (bool) $db
            ->query(sprintf("SELECT to_regclass('public.\"%s\"')", $candidate))
            ->fetchColumn();
        if ($quoted) {
            return sprintf('"%s"', $candidate);
        }
    }

    return null;
}

$source = connect($sourceUrl);
$target = connect($targetUrl);

$hasDifferences = false;

foreach ($tables as $table) {
    if (in_array($table, $skipTables, true)) {
        continue;
    }
    $sourceCandidates = $sourceTableMap[$table] ?? [$table];
    $sourceTable = resolveTable($source, $sourceCandidates);
    $sourceExists = $sourceTable !== null;
    $targetExists = (bool) $target
        ->query(sprintf("SELECT to_regclass('public.%s')", $table))
        ->fetchColumn();

    if (!$sourceExists || !$targetExists) {
        $hasDifferences = true;
        printf(
            "%s: source=%s target=%s\n",
            $table,
            $sourceExists ? 'exists' : 'missing',
            $targetExists ? 'exists' : 'missing'
        );
        continue;
    }

    $sourceCount = (int) $source->query(sprintf('SELECT COUNT(*) FROM public.%s', $sourceTable))->fetchColumn();
    $targetCount = (int) $target->query(sprintf('SELECT COUNT(*) FROM public.%s', $table))->fetchColumn();

    if ($sourceCount !== $targetCount) {
        $hasDifferences = true;
        printf("%s: source=%d target=%d\n", $table, $sourceCount, $targetCount);
    }
}

if ($hasDifferences) {
    exit(2);
}

echo "Counts match for all tables.\n";
