<?php

declare(strict_types=1);

/**
 * Migrate CustomFieldValues from orphaned CustomField definitions to current ones.
 *
 * When SkeletonStructureService::updateCustomFields() runs without IDs from the frontend,
 * it deletes old CustomField definitions and creates new ones. But the FK on custom_fields
 * is SET NULL (not CASCADE), so old CFs become orphaned (all type FKs = NULL) and their
 * CFValues still exist but point to the wrong CF.
 *
 * This script:
 * 1. For each entity (composant, piece, product) with CFValues pointing to orphaned CFs,
 *    find the matching current CF by name on the entity's ModelType
 * 2. Reassign the CFValue to the current CF
 * 3. Delete orphaned CF definitions that no longer have any values
 *
 * Usage: php scripts/migrate-orphaned-custom-fields.php [--dry-run]
 */

require_once __DIR__.'/../vendor/autoload.php';

use Doctrine\DBAL\DriverManager;

$dryRun = in_array('--dry-run', $argv, true);

$env  = getenv('APP_ENV') ?: 'local';
$conn = DriverManager::getConnection(match ($env) {
    'prod' => [
        'driver'   => 'pdo_pgsql',
        'host'     => 'localhost',
        'port'     => 5432,
        'dbname'   => getenv('DB_NAME') ?: 'inventory',
        'user'     => 'ferme_user',
        'password' => 'fermerecette',
    ],
    default => [
        'driver'   => 'pdo_pgsql',
        'host'     => 'db',
        'port'     => 5432,
        'dbname'   => 'inventory',
        'user'     => 'root',
        'password' => 'root',
    ],
});

echo $dryRun ? "=== DRY RUN MODE ===\n\n" : "=== LIVE MODE ===\n\n";

$migratedCount  = 0;
$deletedCfCount = 0;
$skippedCount   = 0;
$conflictCount  = 0;

// Process each entity type
$entityTypes = [
    [
        'label'         => 'composant',
        'entityTable'   => 'composants',
        'cfvFk'         => 'composantid',
        'modelTypeFk'   => 'typecomposantid',
        'cfModelTypeFk' => 'typecomposantid',
    ],
    [
        'label'         => 'piece',
        'entityTable'   => 'pieces',
        'cfvFk'         => 'pieceid',
        'modelTypeFk'   => 'typepieceid',
        'cfModelTypeFk' => 'typepieceid',
    ],
    [
        'label'         => 'product',
        'entityTable'   => 'products',
        'cfvFk'         => 'productid',
        'modelTypeFk'   => 'typeproductid',
        'cfModelTypeFk' => 'typeproductid',
    ],
];

foreach ($entityTypes as $et) {
    echo sprintf("--- Processing %ss ---\n\n", $et['label']);

    // Find all CFValues pointing to orphaned CFs for this entity type
    $orphanedValues = $conn->fetchAllAssociative("
        SELECT cfv.id as cfv_id, cfv.value, cfv.{$et['cfvFk']} as entity_id,
               cf_old.id as old_cf_id, cf_old.name as field_name,
               e.name as entity_name, e.{$et['modelTypeFk']} as model_type_id
        FROM custom_field_values cfv
        JOIN custom_fields cf_old ON cf_old.id = cfv.customfieldid
        JOIN {$et['entityTable']} e ON e.id = cfv.{$et['cfvFk']}
        WHERE cfv.{$et['cfvFk']} IS NOT NULL
          AND cf_old.{$et['cfModelTypeFk']} IS NULL
          AND cf_old.typecomposantid IS NULL
          AND cf_old.typepieceid IS NULL
          AND cf_old.typeproductid IS NULL
        ORDER BY e.name, cf_old.name
    ");

    echo sprintf("  Found %d orphaned custom field values.\n", count($orphanedValues));

    foreach ($orphanedValues as $ov) {
        if (!$ov['model_type_id']) {
            echo sprintf("  SKIP: %s '%s' has no ModelType\n", $et['label'], $ov['entity_name']);
            ++$skippedCount;

            continue;
        }

        // Find the current CF definition on the ModelType with the same name
        $currentCf = $conn->fetchAssociative("
            SELECT id FROM custom_fields
            WHERE {$et['cfModelTypeFk']} = ? AND name = ?
            LIMIT 1
        ", [$ov['model_type_id'], $ov['field_name']]);

        if (!$currentCf) {
            echo sprintf(
                "  WARNING: No current CF '%s' on ModelType %s for %s '%s'\n",
                $ov['field_name'],
                $ov['model_type_id'],
                $et['label'],
                $ov['entity_name']
            );
            ++$skippedCount;

            continue;
        }

        // Check if entity already has a CFValue for this current CF
        $existingValue = $conn->fetchAssociative("
            SELECT id, value FROM custom_field_values
            WHERE {$et['cfvFk']} = ? AND customfieldid = ?
        ", [$ov['entity_id'], $currentCf['id']]);

        if ($existingValue) {
            // Current CF already has a value for this entity
            if ('' !== $existingValue['value'] && null !== $existingValue['value']) {
                // Both have values — conflict, skip
                if ('' !== $ov['value'] && null !== $ov['value'] && $ov['value'] !== $existingValue['value']) {
                    echo sprintf(
                        "  CONFLICT: %s '%s' field '%s': old='%s' vs current='%s' — keeping current\n",
                        $et['label'],
                        $ov['entity_name'],
                        $ov['field_name'],
                        $ov['value'],
                        $existingValue['value']
                    );
                    ++$conflictCount;
                }
                // Delete the orphaned value (current one is kept)
                if (!$dryRun) {
                    $conn->executeStatement('DELETE FROM custom_field_values WHERE id = ?', [$ov['cfv_id']]);
                }
                echo sprintf(
                    "  DELETE orphaned: %s '%s' field '%s' (current has value '%s')\n",
                    $et['label'],
                    $ov['entity_name'],
                    $ov['field_name'],
                    $existingValue['value']
                );
            } else {
                // Current value is empty, orphaned has data — update the current one and delete orphaned
                if ('' !== $ov['value'] && null !== $ov['value']) {
                    echo sprintf(
                        "  MIGRATE: %s '%s' field '%s' = '%s'\n",
                        $et['label'],
                        $ov['entity_name'],
                        $ov['field_name'],
                        $ov['value']
                    );
                    if (!$dryRun) {
                        $conn->executeStatement(
                            'UPDATE custom_field_values SET value = ? WHERE id = ?',
                            [$ov['value'], $existingValue['id']]
                        );
                    }
                    ++$migratedCount;
                }
                // Delete the orphaned CFV
                if (!$dryRun) {
                    $conn->executeStatement('DELETE FROM custom_field_values WHERE id = ?', [$ov['cfv_id']]);
                }
            }
        } else {
            // No current CFV exists — reassign the orphaned one to the current CF
            echo sprintf(
                "  REASSIGN: %s '%s' field '%s' = '%s'\n",
                $et['label'],
                $ov['entity_name'],
                $ov['field_name'],
                $ov['value']
            );
            if (!$dryRun) {
                $conn->executeStatement(
                    'UPDATE custom_field_values SET customfieldid = ? WHERE id = ?',
                    [$currentCf['id'], $ov['cfv_id']]
                );
            }
            ++$migratedCount;
        }
    }

    echo "\n";
}

// Clean up orphaned CF definitions with no remaining values
echo "--- Cleaning up orphaned CustomField definitions ---\n\n";

$orphanedCfs = $conn->fetchAllAssociative('
    SELECT cf.id, cf.name
    FROM custom_fields cf
    WHERE cf.typecomposantid IS NULL
      AND cf.typepieceid IS NULL
      AND cf.typeproductid IS NULL
      AND NOT EXISTS (SELECT 1 FROM custom_field_values cfv WHERE cfv.customfieldid = cf.id)
    ORDER BY cf.name
');

echo sprintf("Found %d orphaned CustomField definitions with no values.\n", count($orphanedCfs));

foreach ($orphanedCfs as $cf) {
    if (!$dryRun) {
        $conn->executeStatement('DELETE FROM custom_fields WHERE id = ?', [$cf['id']]);
    }
    ++$deletedCfCount;
}

echo sprintf("\n=== SUMMARY ===\n");
echo sprintf("Values migrated/reassigned: %d\n", $migratedCount);
echo sprintf("Orphaned CF definitions deleted: %d\n", $deletedCfCount);
echo sprintf("Skipped: %d\n", $skippedCount);
echo sprintf("Conflicts (kept current): %d\n", $conflictCount);
echo "=== DONE ===\n";
