<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * Quién apagó un entorno, cuándo y por qué.
 *
 * **Lo que había: nada, y encima no funcionaba.** El estado de un entorno se cambiaba con
 * una casilla «Activo» dentro del formulario de edición, junto al nombre y el dominio. Dos
 * problemas, y el segundo era peor que el primero:
 *
 * 1. La casilla estaba validada con `sometimes|accepted`, y `accepted` exige que el valor
 *    sea verdadero. Desmarcarla y guardar daba «The active field must be accepted» y el
 *    entorno **se quedaba activo**: no había forma de apagar un entorno desde el panel.
 * 2. Aun funcionando, apagar un entorno hace que su Moodle reciba `403 Entorno inactivo`
 *    en la siguiente petición y deje de recibir licencias y contenido, y eso pasaba sin
 *    confirmación, sin decir a qué afecta y **sin dejar rastro de quién lo hizo**.
 *
 * Estas tres columnas son las mismas que ya tienen `clients` y `license_tokens`, por la
 * misma razón: cuando un cliente dice «llevamos dos semanas sin contenido», la pregunta
 * que hay que poder responder es quién lo apagó y por qué, y eso no se deduce de un
 * booleano.
 *
 * No hay relleno: los entornos que ya estén apagados se quedan sin motivo, que es la
 * verdad —nadie lo anotó— y es lo que la pantalla dice en lugar de inventarlo.
 */
return new class extends Migration
{
    public function up(): void
    {
        if (Schema::hasColumn('environments', 'deactivated_at')) {
            return;
        }

        Schema::table('environments', function (Blueprint $table) {
            $table->timestamp('deactivated_at')->nullable()->after('active');

            // `nullOnDelete`: si se borra el usuario que lo apagó, la fecha y el motivo
            // siguen valiendo. Perder el registro entero por dar de baja a un compañero
            // sería perder justo la información que se consulta.
            $table->foreignId('deactivated_by')
                ->nullable()
                ->after('deactivated_at')
                ->constrained('users')
                ->nullOnDelete();

            $table->string('deactivation_reason', 500)->nullable()->after('deactivated_by');
        });

        self::recomponerElIndiceDelDominio();
    }

    /**
     * **El `constrained()` de arriba tiene un efecto secundario en sqlite.**
     *
     * Añadir una clave ajena obliga a sqlite a reconstruir la tabla entera: Laravel copia
     * los datos a una tabla nueva y recrea los índices a partir de lo que sabe de ellos,
     * **perdiendo la cláusula `WHERE`** de los índices parciales. El del dominio es
     * parcial a propósito —único solo entre entornos no locales, porque varios
     * desarrolladores comparten `moodle.test` (fixes/PRODSECU-192)— y salía de aquí
     * convertido en un unique normal:
     *
     * ```sql
     * CREATE UNIQUE INDEX "environments_domain_unique" on "environments" ("domain")
     * ```
     *
     * En producción (MariaDB) no pasa nada: ahí la regla la lleva la columna generada
     * `domain_unique` y un ALTER es un ALTER. Pero **la suite corre sobre sqlite**, así
     * que el efecto es que un test del comportamiento documentado falla por un motivo que
     * no existe en producción. Ya pasó una vez con la migración del cifrado del token, y
     * está contado en `2026_09_02_140000_restore_partial_domain_index`.
     *
     * Se recompone aquí, en la misma migración que lo rompe, y no en otra posterior: así
     * la tabla nunca queda en el estado malo, ni siquiera entre dos migraciones.
     */
    private static function recomponerElIndiceDelDominio(): void
    {
        if (Schema::getConnection()->getDriverName() === 'mysql') {
            return;
        }

        DB::statement('DROP INDEX IF EXISTS environments_domain_unique');
        DB::statement("
            CREATE UNIQUE INDEX environments_domain_unique
            ON environments (domain)
            WHERE env <> 'local'
        ");
    }

    public function down(): void
    {
        Schema::table('environments', function (Blueprint $table) {
            $table->dropConstrainedForeignId('deactivated_by');
            $table->dropColumn(['deactivated_at', 'deactivation_reason']);
        });

        // Quitar la clave ajena reconstruye la tabla igual que ponerla: el índice parcial
        // se pierde también al revertir.
        self::recomponerElIndiceDelDominio();
    }
};
