<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
 * M0 — Catalog : creation des tables `category_type` (referentiel) et `category`.
 *
 * Le referentiel `category_type` est cree vide ; ses valeurs seront seedees
 * ulterieurement (cf. spec-back M0 § 9 HP-1).
 *
 * Index unique partiel sur (LOWER(name), category_type_id) WHERE deleted_at
 * IS NULL : permet la recreation d'une categorie apres suppression logique
 * (cf. RG-1.07). Postgres supporte nativement le `CREATE UNIQUE INDEX ... WHERE`.
 *
 * Les 4 colonnes Timestampable/Blamable (`created_at`, `updated_at`,
 * `created_by`, `updated_by`) materialisent le pattern Shared (cf. ERP-52,
 * spec-back M0 § 2.8) : NOT NULL pour les dates (remplies par le subscriber),
 * nullable + ON DELETE SET NULL pour les FK user (creation hors contexte HTTP
 * et suppression d'un user sans bloquer les categories existantes).
 *
 * Migration placee au namespace racine `DoctrineMigrations` (regle ABSOLUE
 * Starseed n°11) : avec plusieurs migrations_paths, Doctrine Migrations 3.x
 * trie par FQCN alphabetique et non par version timestamp → l'init des tables
 * d'un module doit vivre au namespace racine pour garantir l'ordre sur base
 * vide.
 */
final class Version20260527164000 extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'M0 Catalog : tables category_type et category, index unique partiel.';
    }

    public function up(Schema $schema): void
    {
        $this->addSql(<<<'SQL'
            CREATE TABLE category_type (
                id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
                code VARCHAR(40) NOT NULL,
                label VARCHAR(120) NOT NULL,
                PRIMARY KEY (id)
            )
            SQL);
        $this->addSql('CREATE UNIQUE INDEX uq_category_type_code ON category_type (code)');

        $this->addSql(<<<'SQL'
            CREATE TABLE category (
                id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
                name VARCHAR(120) NOT NULL,
                category_type_id INT NOT NULL,
                deleted_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL,
                created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
                updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
                created_by INT DEFAULT NULL,
                updated_by INT DEFAULT NULL,
                PRIMARY KEY (id),
                CONSTRAINT fk_category_type
                    FOREIGN KEY (category_type_id) REFERENCES category_type (id) ON DELETE RESTRICT,
                CONSTRAINT fk_category_created_by
                    FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL,
                CONSTRAINT fk_category_updated_by
                    FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL
            )
            SQL);

        // Unicite (name, type) case-insensitive, seulement sur les non-soft-deleted.
        $this->addSql(<<<'SQL'
            CREATE UNIQUE INDEX uq_category_name_type_active
            ON category (LOWER(name), category_type_id)
            WHERE deleted_at IS NULL
            SQL);

        $this->addSql('CREATE INDEX idx_category_deleted_at ON category (deleted_at)');
        $this->addSql('CREATE INDEX idx_category_type_id ON category (category_type_id)');
        $this->addSql('CREATE INDEX idx_category_created_by ON category (created_by)');
        $this->addSql('CREATE INDEX idx_category_updated_by ON category (updated_by)');
    }

    public function down(Schema $schema): void
    {
        // Ordre important : `category` porte les FK vers `category_type`.
        $this->addSql('DROP TABLE category');
        $this->addSql('DROP TABLE category_type');
    }
}
