<?php

declare(strict_types=1);

namespace DoctrineMigrations;

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

/**
 * ERP-84 — Taxonomie FOURNISSEUR (module Catalog, prerequis M2).
 *
 * Contexte : ERP-78 (Version20260602100000) a unifie la taxonomie sur un type
 * unique CLIENT. Le M2 (fournisseurs) a besoin d'une taxonomie distincte : les
 * categories clients (Agro-alimentaire...) ne sont pas valides pour un
 * fournisseur (Negociant, Cooperative...). Decision Matthieu (02/06) : types
 * distincts CLIENT / FOURNISSEUR (PRESTA a venir), chacun avec sa taxonomie.
 *
 * Cette migration :
 *  1. recree le `category_type` FOURNISSEUR (code FOURNISSEUR, label « Fournisseur ») ;
 *  2. seede quelques `Category` de demonstration rattachees a ce type.
 *
 * Aucune colonne creee/modifiee -> pas de `COMMENT ON COLUMN` (regle ABSOLUE n°12).
 *
 * Namespace racine `DoctrineMigrations` (regle ABSOLUE n°11) et NON modulaire
 * Catalog : avec plusieurs migrations_paths, Doctrine Migrations 3.x trie par
 * FQCN alphabetique -> une migration `App\Module\Catalog\...` passerait avant les
 * `DoctrineMigrations\...` sur base vide, donc avant la creation de la table
 * `category_type`. Le namespace racine garantit l'ordre par timestamp.
 *
 * Idempotence : `INSERT ... ON CONFLICT (code) DO NOTHING` pour le type,
 * `INSERT ... SELECT ... WHERE NOT EXISTS` pour chaque categorie (aligne sur le
 * pattern ERP-78 etape 4). En prod la table `category` est vide (aucune fixture
 * metier). En dev/test, le purger Doctrine vide `category`/`category_type` avant
 * les fixtures qui reproduisent le meme etat final (CategoryTypeFixtures /
 * CategoryFixtures etendus a FOURNISSEUR).
 */
final class Version20260605120000 extends AbstractMigration
{
    /**
     * Categories de demonstration du type FOURNISSEUR : nom => code stable. Le
     * code est la cle metier (slug MAJUSCULE du nom, miroir du
     * CategoryCodeGenerator) et reste unique parmi les actifs (uq_category_code,
     * partage avec les codes CLIENT — aucune collision ici).
     */
    private const array SUPPLIER_CATEGORIES = [
        'Négociant'   => 'NEGOCIANT',
        'Coopérative' => 'COOPERATIVE',
        'Producteur'  => 'PRODUCTEUR',
        'Grossiste'   => 'GROSSISTE',
        'Importateur' => 'IMPORTATEUR',
    ];

    public function getDescription(): string
    {
        return 'ERP-84 : recree le CategoryType FOURNISSEUR + seed des categories fournisseurs (Negociant, Cooperative...).';
    }

    public function up(Schema $schema): void
    {
        // 1. Type FOURNISSEUR (idempotent via l'index unique uq_category_type_code).
        $this->addSql(<<<'SQL'
            INSERT INTO category_type (code, label) VALUES ('FOURNISSEUR', 'Fournisseur')
            ON CONFLICT (code) DO NOTHING
            SQL);

        // 2. Categories de demonstration sous FOURNISSEUR (si le code est libre
        //    parmi les actifs). created_at/updated_at NOT NULL -> NOW() ; le blame
        //    reste null (seed hors contexte HTTP, libelle « Systeme » cote front).
        foreach (self::SUPPLIER_CATEGORIES as $name => $code) {
            $this->addSql(<<<'SQL'
                INSERT INTO category (name, code, category_type_id, created_at, updated_at)
                SELECT :name, :code, ct.id, NOW(), NOW()
                FROM category_type ct
                WHERE ct.code = 'FOURNISSEUR'
                  AND NOT EXISTS (
                      SELECT 1 FROM category c WHERE c.code = :code AND c.deleted_at IS NULL
                  )
                SQL, ['name' => $name, 'code' => $code]);
        }
    }

    public function down(Schema $schema): void
    {
        // Best-effort : on retire d'abord les categories seedees (par code), puis
        // le type s'il n'est plus reference (guard NOT EXISTS sur la FK RESTRICT).
        $this->addSql(
            'DELETE FROM category WHERE code IN (:codes) '
            ."AND category_type_id = (SELECT id FROM category_type WHERE code = 'FOURNISSEUR')",
            ['codes' => array_values(self::SUPPLIER_CATEGORIES)],
            ['codes' => \Doctrine\DBAL\ArrayParameterType::STRING],
        );

        $this->addSql(<<<'SQL'
            DELETE FROM category_type
            WHERE code = 'FOURNISSEUR'
              AND NOT EXISTS (
                  SELECT 1 FROM category c WHERE c.category_type_id = category_type.id
              )
            SQL);
    }
}
