#!/usr/bin/env php
<?php
/**
 * CLI de siembra.
 *
 *   php bin/seed                  Perfil `base`
 *   php bin/seed base             Núcleo, catálogos y nómina base
 *   php bin/seed modulos          Base más los módulos funcionales
 *   php bin/seed completo         Todo, incluidos los escenarios demo
 *   php bin/seed CargosSeeder     Una sola semilla, por su nombre de clase
 *   php bin/seed --list           Perfiles y semillas disponibles
 *   php bin/seed --validate       Revisión estática, sin tocar la base
 *   php bin/seed --verify-demo    Cobertura de datos por módulo
 *
 * El orden de ejecución lo fija el prefijo numérico de cada archivo de
 * database/seeders; ver database/seeders/support/SeederManifest.php.
 */

$basePath = dirname(__DIR__);
define('BASE_PATH', $basePath . '/');

$argumento = isset($argv[1]) ? $argv[1] : 'base';

// --- Revisión estática: no necesita base de datos -------------------------
if ($argumento === '--validate') {
    require $basePath . '/database/DatabaseStructureAuditor.php';
    $auditor = new DatabaseStructureAuditor();
    exit($auditor->printReport($auditor->audit(
        $basePath . '/database/migrations',
        $basePath . '/database/seeders'
    )));
}

// --- Carga de clases ------------------------------------------------------
// El soporte va primero: las semillas extienden Seeder y consultan
// ClavesDeNegocio en tiempo de construcción del SQL.
foreach (array('ClavesDeNegocio', 'Seeder', 'SeederPipeline', 'SeederManifest') as $soporte) {
    require_once $basePath . '/database/seeders/support/' . $soporte . '.php';
}

SeederManifest::usarDirectorio($basePath . '/database/seeders');

foreach (SeederManifest::todosLosArchivos() as $archivo) {
    require_once $archivo;
}

// Semillas heredadas que aún no se han numerado. Los archivos execute_* son
// ejecutores web con guardas que llaman a die(): no forman parte del CLI.
foreach (glob($basePath . '/database/seeders/*.php') as $archivo) {
    if (strpos(basename($archivo), 'execute_') === 0) {
        continue;
    }
    require_once $archivo;
}

if ($argumento === '--list') {
    echo "Perfiles:\n";
    foreach (SeederManifest::perfiles() as $nombre => $definicion) {
        printf("  %-10s %s\n", $nombre, $definicion['descripcion']);
        foreach (SeederManifest::semillasDe($nombre) as $semilla) {
            printf("             · %s\n", $semilla['file']);
        }
    }

    echo "\nAlias heredados:\n";
    foreach (SeederManifest::alias() as $alias => $perfil) {
        printf("  %-14s -> %s\n", $alias, $perfil);
    }

    exit(0);
}

// --- Conexión -------------------------------------------------------------
// Variables de entorno: se cargan ANTES que Config para que
// Config::syncConfigFromEnv() vea el fichero .env de la raiz. El CLI no pasa
// por core/AutoLoad.php, asi que hay que cargarlas aqui explicitamente.
require_once $basePath . '/core/Env.php';
Env::load($basePath . '/.env');

if (file_exists($basePath . '/app/config/Config.php')) {
    require $basePath . '/app/config/Config.php';
}
if (file_exists($basePath . '/app/config/ConfigEnv.local.php')) {
    require $basePath . '/app/config/ConfigEnv.local.php';
} elseif (file_exists($basePath . '/app/config/ConfigEnv.php')) {
    require $basePath . '/app/config/ConfigEnv.php';
}

// Inyecta el .env en las propiedades estaticas de Config (DB_CONNECTIONS
// incluido). Despues de ConfigEnv, para que el entorno tenga la ultima palabra.
if (class_exists('Config') && method_exists('Config', 'syncConfigFromEnv')) {
    Config::syncConfigFromEnv();
}

$dbConfig = null;
if (class_exists('ConfigEnv') && property_exists('ConfigEnv', 'DB_CONNECTIONS')) {
    $conexiones = ConfigEnv::$DB_CONNECTIONS;
    if (isset($conexiones['klee'])) {
        $dbConfig = $conexiones['klee'];
    }
}

if (!$dbConfig) {
    $dbConfig = array(
        'driver' => Env::get('DB_DRIVER', 'mysql'),
        'host' => Env::get('DB_HOST', 'localhost'),
        'dbname' => Env::get('DB_NAME', ''),
        'user' => Env::get('DB_USER', ''),
        'password' => Env::get('DB_PASSWORD', Env::get('DB_PASS', '')),
    );
}

if (empty($dbConfig['host']) || empty($dbConfig['dbname']) || empty($dbConfig['user'])) {
    fwrite(STDERR, "No se encontró la configuración de base de datos.\n"
        . "Defina DB_HOST, DB_NAME y DB_USER en el fichero .env de la raiz "
        . "(o como variables de entorno).\n");
    exit(1);
}

if (($dbConfig['driver'] ?? 'mysql') !== 'mysql') {
    fwrite(STDERR, "Driver no soportado: " . $dbConfig['driver'] . "\n");
    exit(1);
}

try {
    $pdo = new PDO(
        "mysql:host={$dbConfig['host']};dbname={$dbConfig['dbname']};charset=utf8mb4",
        $dbConfig['user'],
        isset($dbConfig['password']) ? $dbConfig['password'] : ''
    );
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    fwrite(STDERR, "Error de conexión: " . $e->getMessage() . "\n");
    exit(1);
}

if ($argumento === '--verify-demo') {
    require_once $basePath . '/database/DemoReadinessVerifier.php';
    $verificador = new DemoReadinessVerifier($pdo);
    exit($verificador->printReport($verificador->verify()));
}

$reportero = function ($linea) {
    echo $linea . "\n";
};

// --- Perfil ---------------------------------------------------------------
$perfil = SeederManifest::resolverPerfil($argumento);

if ($perfil !== null) {
    echo "Perfil {$perfil}\n";
    $resultado = (new SeederPipeline($pdo, $reportero))->run(SeederManifest::semillasDe($perfil));

    printf(
        "\n%d ejecutada(s), %d omitida(s), %d con error.\n",
        count($resultado['executed']),
        count($resultado['skipped']),
        count($resultado['failed'])
    );

    try {
        SeederPipeline::exigirExito($resultado, $perfil);
    } catch (Throwable $e) {
        fwrite(STDERR, $e->getMessage() . "\n");
        exit(1);
    }

    exit(0);
}

// --- Una sola semilla por nombre de clase ---------------------------------
if (!class_exists($argumento)) {
    fwrite(STDERR, "No existe el perfil ni la clase: {$argumento}\n"
        . "Use php bin/seed --list para ver lo disponible.\n");
    exit(1);
}

try {
    $semilla = new $argumento($pdo);
    if (!method_exists($semilla, 'run')) {
        fwrite(STDERR, "{$argumento} no implementa run()\n");
        exit(1);
    }
    $semilla->run();
    echo "  [ok]        {$argumento}\n";
} catch (Throwable $e) {
    fwrite(STDERR, "  [error]     {$argumento} — " . $e->getMessage() . "\n");
    exit(1);
}

exit(0);
