-- =====================================================
-- V3.0 — Optimisation de la structure de données
-- =====================================================
-- Cat.1  : Table types_reference
-- Cat.2  : Table paiements_objets + suppression
--          colonnes adresse de organisations
-- Cat.4  : Refonte pieces_jointes (polymorphique)
-- Cat.5  : Colonnes Membre manquantes
-- =====================================================

-- ─────────────────────────────────────────────────────
-- Cat.1 — types_reference
-- ─────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS types_reference (
    id            UUID PRIMARY KEY,
    domaine       VARCHAR(100)  NOT NULL,
    code          VARCHAR(100)  NOT NULL,
    libelle       VARCHAR(255)  NOT NULL,
    description   VARCHAR(1000),
    ordre         INT           NOT NULL DEFAULT 0,
    valeur_systeme BOOLEAN      NOT NULL DEFAULT FALSE,
    actif         BOOLEAN       NOT NULL DEFAULT TRUE,
    date_creation     TIMESTAMP NOT NULL DEFAULT NOW(),
    date_modification TIMESTAMP,
    cree_par      VARCHAR(255),
    modifie_par   VARCHAR(255),
    version       BIGINT        NOT NULL DEFAULT 0,
    CONSTRAINT uk_type_ref_domaine_code
        UNIQUE (domaine, code)
);

CREATE INDEX IF NOT EXISTS idx_tr_domaine
    ON types_reference (domaine);
CREATE INDEX IF NOT EXISTS idx_tr_actif
    ON types_reference (actif);

-- ─────────────────────────────────────────────────────────────────────────────
-- Bloc d'idempotence : corrige l'écart entre la table créée par Hibernate
-- (sans DEFAULT SQL) et le schéma attendu par cette migration.
-- Hibernate gère les defaults en Java ; ici on les pose au niveau PostgreSQL.
-- ─────────────────────────────────────────────────────────────────────────────
ALTER TABLE types_reference 
    ADD COLUMN IF NOT EXISTS valeur_systeme  BOOLEAN   NOT NULL DEFAULT FALSE;

ALTER TABLE types_reference
    ADD COLUMN IF NOT EXISTS ordre          INT       NOT NULL DEFAULT 0,
    ADD COLUMN IF NOT EXISTS actif          BOOLEAN   NOT NULL DEFAULT TRUE,
    ADD COLUMN IF NOT EXISTS version        BIGINT    NOT NULL DEFAULT 0,
    ADD COLUMN IF NOT EXISTS date_creation  TIMESTAMP NOT NULL DEFAULT NOW(),
    ADD COLUMN IF NOT EXISTS est_defaut     BOOLEAN   NOT NULL DEFAULT FALSE,
    ADD COLUMN IF NOT EXISTS est_systeme    BOOLEAN   NOT NULL DEFAULT FALSE,
    ADD COLUMN IF NOT EXISTS ordre_affichage INT      NOT NULL DEFAULT 0;

-- Garantit que la contrainte UNIQUE existe (nécessaire pour ON CONFLICT ci-dessous)
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_constraint
        WHERE conname = 'uk_type_ref_domaine_code'
          AND conrelid = 'types_reference'::regclass
    ) THEN
        ALTER TABLE types_reference
            ADD CONSTRAINT uk_type_ref_domaine_code UNIQUE (domaine, code);
    END IF;
END $$;

-- Données initiales : domaines référencés par les entités
-- Toutes les colonnes NOT NULL sont fournies (table peut exister sans DEFAULT si créée par Hibernate)
INSERT INTO types_reference (id, domaine, code, libelle, valeur_systeme, cree_par, actif, ordre, version, date_creation, est_defaut, est_systeme, ordre_affichage)
VALUES
  -- OBJET_PAIEMENT (Cat.2 — PaiementObjet)
  (gen_random_uuid(), 'OBJET_PAIEMENT', 'COTISATION',    'Cotisation',            TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'OBJET_PAIEMENT', 'ADHESION',      'Adhésion',              TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'OBJET_PAIEMENT', 'EVENEMENT',     'Événement',             TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'OBJET_PAIEMENT', 'AIDE',          'Aide',                  TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  -- ENTITE_RATTACHEE (Cat.4 — PieceJointe)
  (gen_random_uuid(), 'ENTITE_RATTACHEE', 'MEMBRE',           'Membre',            TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'ENTITE_RATTACHEE', 'ORGANISATION',     'Organisation',      TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'ENTITE_RATTACHEE', 'COTISATION',       'Cotisation',        TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'ENTITE_RATTACHEE', 'ADHESION',         'Adhésion',          TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'ENTITE_RATTACHEE', 'AIDE',             'Aide',              TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'ENTITE_RATTACHEE', 'TRANSACTION_WAVE', 'Transaction Wave',  TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  -- STATUT_MATRIMONIAL (Cat.5 — Membre)
  (gen_random_uuid(), 'STATUT_MATRIMONIAL', 'CELIBATAIRE', 'Célibataire',  TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'STATUT_MATRIMONIAL', 'MARIE',       'Marié(e)',     TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'STATUT_MATRIMONIAL', 'DIVORCE',     'Divorcé(e)',   TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'STATUT_MATRIMONIAL', 'VEUF',        'Veuf/Veuve',   TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  -- TYPE_IDENTITE (Cat.5 — Membre)
  (gen_random_uuid(), 'TYPE_IDENTITE', 'CNI',        'Carte Nationale d''Identité', TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'TYPE_IDENTITE', 'PASSEPORT',  'Passeport',                   TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'TYPE_IDENTITE', 'PERMIS',     'Permis de conduire',          TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0),
  (gen_random_uuid(), 'TYPE_IDENTITE', 'CARTE_SEJOUR','Carte de séjour',            TRUE, 'system', TRUE, 0, 0, NOW(), FALSE, TRUE, 0)
ON CONFLICT (domaine, code) DO NOTHING;

-- ─────────────────────────────────────────────────────
-- Cat.2 — paiements_objets (remplace 4 tables)
-- ─────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS paiements_objets (
    id               UUID PRIMARY KEY,
    paiement_id      UUID          NOT NULL
        REFERENCES paiements(id),
    type_objet_cible VARCHAR(50)   NOT NULL,
    objet_cible_id   UUID          NOT NULL,
    montant_applique NUMERIC(14,2) NOT NULL,
    date_application TIMESTAMP,
    commentaire      VARCHAR(500),
    actif            BOOLEAN       NOT NULL DEFAULT TRUE,
    date_creation     TIMESTAMP    NOT NULL DEFAULT NOW(),
    date_modification TIMESTAMP,
    cree_par         VARCHAR(255),
    modifie_par      VARCHAR(255),
    version          BIGINT        NOT NULL DEFAULT 0,
    CONSTRAINT uk_paiement_objet
        UNIQUE (paiement_id, type_objet_cible, objet_cible_id)
);

CREATE INDEX IF NOT EXISTS idx_po_paiement
    ON paiements_objets (paiement_id);
CREATE INDEX IF NOT EXISTS idx_po_objet
    ON paiements_objets (type_objet_cible, objet_cible_id);
CREATE INDEX IF NOT EXISTS idx_po_type
    ON paiements_objets (type_objet_cible);

-- ─────────────────────────────────────────────────────
-- Cat.2 — Suppression colonnes adresse de organisations
-- ─────────────────────────────────────────────────────
ALTER TABLE organisations
    DROP COLUMN IF EXISTS adresse,
    DROP COLUMN IF EXISTS ville,
    DROP COLUMN IF EXISTS code_postal,
    DROP COLUMN IF EXISTS region,
    DROP COLUMN IF EXISTS pays;

-- ─────────────────────────────────────────────────────
-- Cat.4 — pieces_jointes → polymorphique
-- ─────────────────────────────────────────────────────
-- Ajout colonnes polymorphiques
ALTER TABLE pieces_jointes
    ADD COLUMN IF NOT EXISTS type_entite_rattachee VARCHAR(50),
    ADD COLUMN IF NOT EXISTS entite_rattachee_id   UUID;

-- Migration des données existantes (colonnes FK explicites ou entite_type/entite_id selon le schéma)
DO $$
BEGIN
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'membre_id') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = 'MEMBRE', entite_rattachee_id = membre_id WHERE membre_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'organisation_id') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = 'ORGANISATION', entite_rattachee_id = organisation_id WHERE organisation_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'cotisation_id') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = 'COTISATION', entite_rattachee_id = cotisation_id WHERE cotisation_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'adhesion_id') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = 'ADHESION', entite_rattachee_id = adhesion_id WHERE adhesion_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'demande_aide_id') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = 'AIDE', entite_rattachee_id = demande_aide_id WHERE demande_aide_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'transaction_wave_id') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = 'TRANSACTION_WAVE', entite_rattachee_id = transaction_wave_id WHERE transaction_wave_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  -- Schéma V1.7 : entite_type / entite_id
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'pieces_jointes' AND column_name = 'entite_type') THEN
    UPDATE pieces_jointes SET type_entite_rattachee = COALESCE(NULLIF(TRIM(entite_type), ''), 'MEMBRE'), entite_rattachee_id = entite_id WHERE entite_id IS NOT NULL AND (type_entite_rattachee IS NULL OR type_entite_rattachee = '');
  END IF;
  -- Valeurs par défaut pour lignes restantes (évite échec NOT NULL)
  UPDATE pieces_jointes SET type_entite_rattachee = COALESCE(NULLIF(TRIM(type_entite_rattachee), ''), 'MEMBRE'), entite_rattachee_id = COALESCE(entite_rattachee_id, (SELECT id FROM utilisateurs LIMIT 1)) WHERE type_entite_rattachee IS NULL OR type_entite_rattachee = '' OR entite_rattachee_id IS NULL;
END $$;

-- Contrainte NOT NULL après migration (seulement si plus aucune ligne NULL)
DO $$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pieces_jointes WHERE type_entite_rattachee IS NULL OR type_entite_rattachee = '' OR entite_rattachee_id IS NULL) THEN
    EXECUTE 'ALTER TABLE pieces_jointes ALTER COLUMN type_entite_rattachee SET NOT NULL';
    EXECUTE 'ALTER TABLE pieces_jointes ALTER COLUMN entite_rattachee_id SET NOT NULL';
  END IF;
END $$;

-- Suppression anciennes FK ou colonnes polymorphiques V1.7 (entite_type, entite_id)
ALTER TABLE pieces_jointes
    DROP COLUMN IF EXISTS membre_id,
    DROP COLUMN IF EXISTS organisation_id,
    DROP COLUMN IF EXISTS cotisation_id,
    DROP COLUMN IF EXISTS adhesion_id,
    DROP COLUMN IF EXISTS demande_aide_id,
    DROP COLUMN IF EXISTS transaction_wave_id,
    DROP COLUMN IF EXISTS entite_type,
    DROP COLUMN IF EXISTS entite_id;

-- Suppression anciens index
DROP INDEX IF EXISTS idx_piece_jointe_membre;
DROP INDEX IF EXISTS idx_piece_jointe_organisation;
DROP INDEX IF EXISTS idx_piece_jointe_cotisation;
DROP INDEX IF EXISTS idx_piece_jointe_adhesion;
DROP INDEX IF EXISTS idx_piece_jointe_demande_aide;
DROP INDEX IF EXISTS idx_piece_jointe_transaction_wave;

-- Nouveaux index polymorphiques
CREATE INDEX IF NOT EXISTS idx_pj_entite
    ON pieces_jointes (type_entite_rattachee, entite_rattachee_id);
CREATE INDEX IF NOT EXISTS idx_pj_type_entite
    ON pieces_jointes (type_entite_rattachee);

-- ─────────────────────────────────────────────────────
-- Cat.5 — Colonnes Membre manquantes (table utilisateurs depuis V2.0)
-- ─────────────────────────────────────────────────────
ALTER TABLE utilisateurs
    ADD COLUMN IF NOT EXISTS statut_matrimonial VARCHAR(50),
    ADD COLUMN IF NOT EXISTS nationalite        VARCHAR(100),
    ADD COLUMN IF NOT EXISTS type_identite      VARCHAR(50),
    ADD COLUMN IF NOT EXISTS numero_identite    VARCHAR(100);

-- ─────────────────────────────────────────────────────
-- Cat.8 — Valeurs par défaut dans configurations
-- ─────────────────────────────────────────────────────
INSERT INTO configurations (id, cle, valeur, type, categorie, description, modifiable, visible, actif, date_creation, cree_par, version)
VALUES
  (gen_random_uuid(), 'defaut.devise',                  'XOF',         'STRING', 'SYSTEME', 'Devise par défaut',                  TRUE, TRUE, TRUE, NOW(), 'system', 0),
  (gen_random_uuid(), 'defaut.statut.organisation',     'ACTIVE',      'STRING', 'SYSTEME', 'Statut initial organisation',        TRUE, TRUE, TRUE, NOW(), 'system', 0),
  (gen_random_uuid(), 'defaut.type.organisation',       'ASSOCIATION', 'STRING', 'SYSTEME', 'Type initial organisation',          TRUE, TRUE, TRUE, NOW(), 'system', 0),
  (gen_random_uuid(), 'defaut.utilisateur.systeme',     'system',      'STRING', 'SYSTEME', 'Identifiant utilisateur système',    FALSE, FALSE, TRUE, NOW(), 'system', 0),
  (gen_random_uuid(), 'defaut.montant.cotisation',      '0',           'NUMBER', 'SYSTEME', 'Montant cotisation par défaut',      TRUE, TRUE, TRUE, NOW(), 'system', 0)
ON CONFLICT DO NOTHING;

-- ─────────────────────────────────────────────────────
-- Cat.7 — Index composites pour requêtes fréquentes
-- ─────────────────────────────────────────────────────
-- Aligner paiements avec l'entité (statut → statut_paiement si la colonne existe)
DO $$
BEGIN
  IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'paiements' AND column_name = 'statut')
     AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'paiements' AND column_name = 'statut_paiement') THEN
    ALTER TABLE paiements RENAME COLUMN statut TO statut_paiement;
  END IF;
END $$;

CREATE INDEX IF NOT EXISTS idx_cotisation_org_statut_annee
    ON cotisations (organisation_id, statut, annee);
CREATE INDEX IF NOT EXISTS idx_cotisation_membre_statut
    ON cotisations (membre_id, statut);
CREATE INDEX IF NOT EXISTS idx_paiement_membre_statut_date
    ON paiements (membre_id, statut_paiement,
                  date_paiement);
CREATE INDEX IF NOT EXISTS idx_notification_membre_statut
    ON notifications (membre_id, statut, date_envoi);
CREATE INDEX IF NOT EXISTS idx_adhesion_org_statut
    ON demandes_adhesion (organisation_id, statut);
CREATE INDEX IF NOT EXISTS idx_aide_org_statut_urgence
    ON demandes_aide (organisation_id, statut, urgence);
CREATE INDEX IF NOT EXISTS idx_membreorg_org_statut
    ON membres_organisations
        (organisation_id, statut_membre);
CREATE INDEX IF NOT EXISTS idx_evenement_org_date_statut
    ON evenements
        (organisation_id, date_debut, statut);

-- ─────────────────────────────────────────────────────
-- Cat.7 — Contraintes CHECK métier
-- ─────────────────────────────────────────────────────
ALTER TABLE cotisations
    ADD CONSTRAINT chk_montant_paye_le_du
    CHECK (montant_paye <= montant_du);
ALTER TABLE souscriptions_organisation
    ADD CONSTRAINT chk_quota_utilise_le_max
    CHECK (quota_utilise <= quota_max);
