<?php

declare(strict_types=1);

/**
 * Script to restore custom field values lost during ModelType sync.
 *
 * Problem: SkeletonStructureService::updateCustomFields() deletes and recreates
 * CustomField definitions when frontend doesn't send IDs. This cascades to
 * deleting all CustomFieldValues.
 *
 * This script:
 * 1. Pieces: Restores values from audit_logs (the "from" values in deletion diffs)
 * 2. Composants: Removes duplicate empty CustomFieldValues created by sync
 *
 * Usage: php scripts/restore-custom-field-values.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";

// ============================================================
// PART 1: Restore piece custom field values from audit logs
// ============================================================
echo "--- PART 1: Restoring piece custom field values ---\n\n";

// Find all deletion audit entries (where values went from X to null on 2026-03-13)
$deletionLogs = $conn->fetchAllAssociative("
    SELECT al.entityid, al.diff::text as diff, p.name as piece_name
    FROM audit_logs al
    JOIN pieces p ON p.id = al.entityid
    WHERE al.entitytype = 'piece'
      AND al.action = 'update'
      AND al.diff::text LIKE '%\"to\":null%'
      AND al.diff::text LIKE '%customField%'
      AND al.createdat >= '2026-03-13'
    ORDER BY p.name
");

echo sprintf("Found %d pieces with deleted custom field values.\n\n", count($deletionLogs));

$restoredCount = 0;
$errorCount    = 0;

foreach ($deletionLogs as $log) {
    $pieceId   = $log['entityid'];
    $pieceName = $log['piece_name'];
    $diff      = json_decode($log['diff'], true);

    foreach ($diff as $key => $change) {
        if (!str_starts_with($key, 'customField:')) {
            continue;
        }
        if (null !== $change['to']) {
            continue; // Not a deletion
        }
        $oldValue = $change['from'];
        if (null === $oldValue || '' === $oldValue) {
            continue; // Nothing to restore
        }

        $fieldName = substr($key, strlen('customField:'));

        // Find the current CustomFieldValue for this piece + field name
        $cfv = $conn->fetchAssociative('
            SELECT cfv.id, cfv.value, cf.name as field_name
            FROM custom_field_values cfv
            JOIN custom_fields cf ON cf.id = cfv.customfieldid
            WHERE cfv.pieceid = ?
              AND cf.name = ?
        ', [$pieceId, $fieldName]);

        if (!$cfv) {
            echo sprintf("  WARNING: No CustomFieldValue found for piece '%s' field '%s' — skipping\n", $pieceName, $fieldName);
            ++$errorCount;

            continue;
        }

        if ('' !== $cfv['value'] && null !== $cfv['value']) {
            echo sprintf("  SKIP: Piece '%s' field '%s' already has value '%s' (would restore '%s')\n", $pieceName, $fieldName, $cfv['value'], $oldValue);

            continue;
        }

        echo sprintf("  RESTORE: Piece '%s' field '%s' = '%s'\n", $pieceName, $fieldName, $oldValue);

        if (!$dryRun) {
            $conn->executeStatement(
                'UPDATE custom_field_values SET value = ? WHERE id = ?',
                [$oldValue, $cfv['id']]
            );
        }
        ++$restoredCount;
    }
}

echo sprintf("\nPieces: %d values restored, %d errors.\n\n", $restoredCount, $errorCount);

// ============================================================
// PART 2: Remove duplicate empty composant CustomFieldValues
// ============================================================
echo "--- PART 2: Cleaning duplicate composant custom field values ---\n\n";

// Find composants that have duplicate CFVs (same composantid + same field name, one with value and one empty)
$duplicates = $conn->fetchAllAssociative("
    SELECT cfv_empty.id as empty_cfv_id, c.name as composant_name, cf_empty.name as field_name,
           cfv_filled.value as existing_value
    FROM custom_field_values cfv_empty
    JOIN custom_fields cf_empty ON cf_empty.id = cfv_empty.customfieldid
    JOIN composants c ON c.id = cfv_empty.composantid
    JOIN custom_field_values cfv_filled ON cfv_filled.composantid = cfv_empty.composantid
    JOIN custom_fields cf_filled ON cf_filled.id = cfv_filled.customfieldid
    WHERE cfv_empty.composantid IS NOT NULL
      AND cfv_empty.value = ''
      AND cf_empty.name = cf_filled.name
      AND cfv_filled.value != ''
      AND cfv_filled.id != cfv_empty.id
    ORDER BY c.name, cf_empty.name
");

echo sprintf("Found %d duplicate empty custom field values on composants.\n\n", count($duplicates));

$deletedDuplicates = 0;
foreach ($duplicates as $dup) {
    echo sprintf(
        "  DELETE empty duplicate: Composant '%s' field '%s' (has value '%s' in other record)\n",
        $dup['composant_name'],
        $dup['field_name'],
        $dup['existing_value']
    );

    if (!$dryRun) {
        $conn->executeStatement('DELETE FROM custom_field_values WHERE id = ?', [$dup['empty_cfv_id']]);
    }
    ++$deletedDuplicates;
}

// Also find composants with duplicate empty CFVs (both empty, same field name - keep one, delete the other)
$emptyDuplicates = $conn->fetchAllAssociative("
    SELECT cfv2.id as duplicate_id, c.name as composant_name, cf2.name as field_name
    FROM custom_field_values cfv1
    JOIN custom_fields cf1 ON cf1.id = cfv1.customfieldid
    JOIN custom_field_values cfv2 ON cfv2.composantid = cfv1.composantid AND cfv2.id > cfv1.id
    JOIN custom_fields cf2 ON cf2.id = cfv2.customfieldid
    JOIN composants c ON c.id = cfv1.composantid
    WHERE cfv1.composantid IS NOT NULL
      AND cfv1.value = ''
      AND cfv2.value = ''
      AND cf1.name = cf2.name
    ORDER BY c.name, cf2.name
");

echo sprintf("\nFound %d duplicate empty-empty custom field values on composants.\n\n", count($emptyDuplicates));

foreach ($emptyDuplicates as $dup) {
    echo sprintf(
        "  DELETE empty-empty duplicate: Composant '%s' field '%s'\n",
        $dup['composant_name'],
        $dup['field_name']
    );

    if (!$dryRun) {
        $conn->executeStatement('DELETE FROM custom_field_values WHERE id = ?', [$dup['duplicate_id']]);
    }
    ++$deletedDuplicates;
}

echo sprintf("\nComposants: %d duplicate values removed.\n", $deletedDuplicates);

echo "\n=== DONE ===\n";
