-- ============================================================================
-- PTA V7 - Socle métier annuel, postes, contraintes et équipes
-- MySQL 8.0.16+
-- À exécuter après le schéma V5.20 / V6.
-- ============================================================================

START TRANSACTION;

-- --------------------------------------------------------------------------
-- 1. Postes éligibles au PTA
-- --------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS poste_agent (
    id_poste INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    code VARCHAR(50) NOT NULL,
    libelle VARCHAR(150) NOT NULL,
    famille ENUM('ANIMATION', 'RESTAURATION_ENTRETIEN') NOT NULL,
    heures_mercredi_minutes SMALLINT UNSIGNED NOT NULL,
    heures_extrascolaire_minutes SMALLINT UNSIGNED NOT NULL,
    autorise_preparation BOOLEAN NOT NULL DEFAULT TRUE,
    peut_assurer_animation BOOLEAN NOT NULL DEFAULT TRUE,
    preparation_lundi_si_100 BOOLEAN NOT NULL DEFAULT FALSE,
    actif BOOLEAN NOT NULL DEFAULT TRUE,
    ordre_affichage SMALLINT UNSIGNED NOT NULL DEFAULT 100,
    CONSTRAINT uk_poste_agent_code UNIQUE (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO poste_agent (
    code, libelle, famille, heures_mercredi_minutes, heures_extrascolaire_minutes,
    autorise_preparation, peut_assurer_animation, preparation_lundi_si_100, ordre_affichage
) VALUES
    ('RESPONSABLE', 'Responsable d’accueil', 'ANIMATION', 570, 570, TRUE, TRUE, TRUE, 10),
    ('ANIMATION_RELAIS', 'Agent d’animation relais', 'ANIMATION', 570, 570, TRUE, TRUE, TRUE, 20),
    ('ANIMATION', 'Agent d’animation', 'ANIMATION', 570, 570, TRUE, TRUE, TRUE, 30),
    ('RESTAURATION_ENTRETIEN', 'Agent de restauration collective et d’entretien', 'RESTAURATION_ENTRETIEN', 420, 420, FALSE, FALSE, FALSE, 40)
ON DUPLICATE KEY UPDATE
    libelle = VALUES(libelle),
    famille = VALUES(famille),
    heures_mercredi_minutes = VALUES(heures_mercredi_minutes),
    heures_extrascolaire_minutes = VALUES(heures_extrascolaire_minutes),
    autorise_preparation = VALUES(autorise_preparation),
    peut_assurer_animation = VALUES(peut_assurer_animation),
    preparation_lundi_si_100 = VALUES(preparation_lundi_si_100),
    ordre_affichage = VALUES(ordre_affichage),
    actif = TRUE;

-- --------------------------------------------------------------------------
-- 2. Compléments métier de l’agent
-- --------------------------------------------------------------------------
ALTER TABLE agent
    ADD COLUMN id_poste INT UNSIGNED NULL AFTER date_debut_contrat,
    ADD COLUMN type_contrat ENUM('PERMANENT', 'TEMPORAIRE') NOT NULL DEFAULT 'PERMANENT' AFTER id_poste,
    ADD COLUMN date_fin_contrat DATE NULL AFTER type_contrat,
    ADD COLUMN formation_repartition_annuelle BOOLEAN NOT NULL DEFAULT FALSE AFTER date_fin_contrat,
    ADD COLUMN commentaire_pta VARCHAR(1000) NULL AFTER formation_repartition_annuelle;

ALTER TABLE agent
    ADD CONSTRAINT fk_agent_poste
        FOREIGN KEY (id_poste) REFERENCES poste_agent(id_poste)
        ON UPDATE CASCADE ON DELETE SET NULL,
    ADD CONSTRAINT chk_agent_dates_contrat_v7
        CHECK (date_fin_contrat IS NULL OR date_debut_contrat IS NULL OR date_fin_contrat >= date_debut_contrat);

CREATE INDEX idx_agent_poste ON agent(id_poste);
CREATE INDEX idx_agent_type_contrat ON agent(type_contrat, actif);

-- --------------------------------------------------------------------------
-- 3. PTA annuel de l’agent
-- --------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS pta_annuel (
    id_pta INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_agent INT UNSIGNED NOT NULL,
    date_debut DATE NOT NULL,
    date_fin DATE NOT NULL,
    quotite_travail DECIMAL(5,2) NOT NULL,
    quota_reference_minutes INT UNSIGNED NOT NULL DEFAULT 96420,
    quota_cible_minutes INT UNSIGNED NOT NULL,
    enveloppe_formation_minutes SMALLINT UNSIGNED NOT NULL DEFAULT 840,
    conges_annuels_jours_cible DECIMAL(5,2) NOT NULL DEFAULT 25.00,
    jours_fractionnement_cible TINYINT UNSIGNED NOT NULL DEFAULT 2,
    statut ENUM('BROUILLON', 'A_CONTROLER', 'VALIDE') NOT NULL DEFAULT 'BROUILLON',
    commentaire VARCHAR(1000) NULL,
    date_validation DATETIME NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    CONSTRAINT fk_pta_annuel_agent
        FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
        ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT chk_pta_annuel_dates CHECK (date_fin >= date_debut),
    CONSTRAINT chk_pta_annuel_quotite CHECK (quotite_travail > 0 AND quotite_travail <= 100),
    CONSTRAINT chk_pta_annuel_quota CHECK (quota_reference_minutes > 0 AND quota_cible_minutes > 0),
    CONSTRAINT uk_pta_annuel_agent_periode UNIQUE (id_agent, date_debut, date_fin),
    INDEX idx_pta_annuel_agent_statut (id_agent, statut),
    INDEX idx_pta_annuel_periode (date_debut, date_fin)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- --------------------------------------------------------------------------
-- 4. Préférences, interdictions et proximité des lieux
-- --------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS agent_structure_souhait (
    id_souhait INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_agent INT UNSIGNED NOT NULL,
    id_structure INT UNSIGNED NOT NULL,
    type_souhait ENUM('PREFERENCE', 'INTERDICTION') NOT NULL,
    priorite TINYINT UNSIGNED NOT NULL DEFAULT 1,
    distance_km DECIMAL(7,2) NULL,
    commentaire VARCHAR(500) NULL,
    actif BOOLEAN NOT NULL DEFAULT TRUE,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    CONSTRAINT fk_souhait_agent FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
        ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_souhait_structure FOREIGN KEY (id_structure) REFERENCES structure(id_structure)
        ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT chk_souhait_priorite CHECK (priorite BETWEEN 1 AND 5),
    CONSTRAINT chk_souhait_distance CHECK (distance_km IS NULL OR distance_km >= 0),
    CONSTRAINT uk_souhait_agent_structure UNIQUE (id_agent, id_structure),
    INDEX idx_souhait_agent_type (id_agent, type_souhait, actif)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- --------------------------------------------------------------------------
-- 5. Contraintes médicales et temps partiels thérapeutiques
-- --------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS agent_contrainte (
    id_contrainte INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_agent INT UNSIGNED NOT NULL,
    type_contrainte ENUM('MEDICALE', 'TEMPS_PARTIEL_THERAPEUTIQUE') NOT NULL,
    date_debut DATE NOT NULL,
    date_fin DATE NULL,
    quotite_temporaire DECIMAL(5,2) NULL,
    maximum_minutes_jour SMALLINT UNSIGNED NULL,
    maximum_minutes_semaine SMALLINT UNSIGNED NULL,
    interdit_matin BOOLEAN NOT NULL DEFAULT FALSE,
    interdit_midi BOOLEAN NOT NULL DEFAULT FALSE,
    interdit_soir BOOLEAN NOT NULL DEFAULT FALSE,
    commentaire VARCHAR(1000) NOT NULL,
    actif BOOLEAN NOT NULL DEFAULT TRUE,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    CONSTRAINT fk_contrainte_agent FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
        ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT chk_contrainte_dates CHECK (date_fin IS NULL OR date_fin >= date_debut),
    CONSTRAINT chk_contrainte_quotite CHECK (quotite_temporaire IS NULL OR (quotite_temporaire > 0 AND quotite_temporaire <= 100)),
    CONSTRAINT chk_contrainte_max_jour CHECK (maximum_minutes_jour IS NULL OR maximum_minutes_jour > 0),
    CONSTRAINT chk_contrainte_max_semaine CHECK (maximum_minutes_semaine IS NULL OR maximum_minutes_semaine > 0),
    INDEX idx_contrainte_agent_dates (id_agent, actif, date_debut, date_fin)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- --------------------------------------------------------------------------
-- 6. Équipes périscolaires des mercredis et extrascolaires
-- --------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS equipe_pta (
    id_equipe INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_structure INT UNSIGNED NOT NULL,
    type_equipe ENUM('MERCREDI_PERISCOLAIRE', 'EXTRASCOLAIRE', 'PERISCOLAIRE_SEMAINE') NOT NULL,
    libelle VARCHAR(180) NOT NULL,
    date_debut DATE NOT NULL,
    date_fin DATE NOT NULL,
    nombre_enfants_moins_6 SMALLINT UNSIGNED NOT NULL DEFAULT 0,
    [REDACTED] SMALLINT UNSIGNED NOT NULL DEFAULT 0,
    ratio_moins_6 TINYINT UNSIGNED NOT NULL DEFAULT 8,
    ratio_6_plus TINYINT UNSIGNED NOT NULL DEFAULT 12,
    minimum_agents TINYINT UNSIGNED NOT NULL DEFAULT 1,
    pourcentage_diplomes_min DECIMAL(5,2) NOT NULL DEFAULT 50.00,
    statut ENUM('BROUILLON', 'A_CONTROLER', 'VALIDEE') NOT NULL DEFAULT 'BROUILLON',
    commentaire VARCHAR(1000) NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    CONSTRAINT fk_equipe_pta_structure FOREIGN KEY (id_structure) REFERENCES structure(id_structure)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT chk_equipe_dates CHECK (date_fin >= date_debut),
    CONSTRAINT chk_equipe_ratios CHECK (ratio_moins_6 > 0 AND ratio_6_plus > 0),
    CONSTRAINT chk_equipe_minimum CHECK (minimum_agents > 0),
    CONSTRAINT chk_equipe_diplomes CHECK (pourcentage_diplomes_min BETWEEN 0 AND 100),
    INDEX idx_equipe_pta_type_dates (type_equipe, date_debut, date_fin),
    INDEX idx_equipe_pta_structure_dates (id_structure, date_debut, date_fin)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE IF NOT EXISTS equipe_pta_membre (
    id_equipe_membre INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_equipe INT UNSIGNED NOT NULL,
    id_agent INT UNSIGNED NOT NULL,
    fonction_equipe ENUM('RESPONSABLE', 'ANIMATION', 'RESTAURATION_ENTRETIEN') NOT NULL DEFAULT 'ANIMATION',
    date_debut DATE NULL,
    date_fin DATE NULL,
    commentaire VARCHAR(500) NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT fk_equipe_membre_equipe FOREIGN KEY (id_equipe) REFERENCES equipe_pta(id_equipe)
        ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_equipe_membre_agent FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT chk_equipe_membre_dates CHECK (date_fin IS NULL OR date_debut IS NULL OR date_fin >= date_debut),
    CONSTRAINT uk_equipe_membre UNIQUE (id_equipe, id_agent),
    INDEX idx_equipe_membre_agent (id_agent, id_equipe)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- --------------------------------------------------------------------------
-- 7. Références horaires des lieux pour les automatismes de préparation
-- --------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS structure_creneau_reference (
    id_reference INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_structure INT UNSIGNED NOT NULL,
    code_plage ENUM('ALP_MATIN', 'RESTAURATION', 'ALP_SOIR') NOT NULL,
    jour_semaine TINYINT UNSIGNED NOT NULL COMMENT '1=lundi ... 5=vendredi',
    heure_debut TIME NOT NULL,
    heure_fin TIME NOT NULL,
    actif BOOLEAN NOT NULL DEFAULT TRUE,

    CONSTRAINT fk_reference_structure FOREIGN KEY (id_structure) REFERENCES structure(id_structure)
        ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT chk_reference_jour CHECK (jour_semaine BETWEEN 1 AND 5),
    CONSTRAINT chk_reference_ordre CHECK (heure_fin > heure_debut),
    CONSTRAINT uk_reference_structure_plage_jour UNIQUE (id_structure, code_plage, jour_semaine),
    INDEX idx_reference_structure_jour (id_structure, jour_semaine, actif)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- --------------------------------------------------------------------------
-- 8. Motifs détaillés du PTA
-- --------------------------------------------------------------------------
INSERT INTO motif_planning (code, libelle, compte_dans_quota, ordre_affichage, actif)
VALUES
    ('ALP_MATIN', 'ALP matin', TRUE, 10, TRUE),
    ('RESTAURATION', 'Restauration', TRUE, 20, TRUE),
    ('ALP_SOIR', 'ALP soir', TRUE, 30, TRUE),
    ('MERCREDI_PERISCOLAIRE', 'Mercredi périscolaire', TRUE, 40, TRUE),
    ('EXTRASCOLAIRE', 'Temps extrascolaire', TRUE, 50, TRUE),
    ('FORMATION', 'Formation', TRUE, 60, TRUE),
    ('CONGE', 'Congé annuel (non décompté)', FALSE, 70, TRUE),
    ('JOUR_FRACTIONNEMENT', 'Journée de fractionnement', TRUE, 80, TRUE),
    ('PREPARATION_PERISCOLAIRE', 'Préparation périscolaire', TRUE, 90, TRUE),
    ('PREPARATION_EXTRASCOLAIRE', 'Préparation extrascolaire', TRUE, 100, TRUE),
    ('PREPARATION_LUNDI', 'Préparation du lundi', TRUE, 110, TRUE),
    ('MENAGE_FOND', 'Ménage de fond', TRUE, 120, TRUE),
    ('JNT', 'Journée non travaillée', FALSE, 130, TRUE)
ON DUPLICATE KEY UPDATE
    libelle = VALUES(libelle),
    compte_dans_quota = VALUES(compte_dans_quota),
    ordre_affichage = VALUES(ordre_affichage),
    actif = TRUE;

-- La règle métier communiquée précise que les congés annuels ne sont pas
-- redécomptés du quota puisqu'ils sont déjà intégrés dans le calcul initial.
UPDATE motif_planning
SET libelle = 'Congé annuel (non décompté)', compte_dans_quota = FALSE
WHERE code = 'CONGE';

-- --------------------------------------------------------------------------
-- 9. Vues de synthèse
-- --------------------------------------------------------------------------
CREATE OR REPLACE VIEW v_pta_annuel_synthese AS
SELECT
    pa.id_pta,
    pa.id_agent,
    a.matricule,
    a.nom,
    a.prenom,
    po.code AS poste_code,
    po.libelle AS poste_libelle,
    a.type_contrat,
    pa.date_debut,
    pa.date_fin,
    pa.quotite_travail,
    pa.quota_cible_minutes,
    COALESCE(SUM(CASE WHEN mp.compte_dans_quota = TRUE THEN TIMESTAMPDIFF(MINUTE, CONCAT(ch.date_jour, ' ', ch.heure_debut), CONCAT(ch.date_jour, ' ', ch.heure_fin)) ELSE 0 END), 0) AS minutes_decomptees,
    pa.quota_cible_minutes - COALESCE(SUM(CASE WHEN mp.compte_dans_quota = TRUE THEN TIMESTAMPDIFF(MINUTE, CONCAT(ch.date_jour, ' ', ch.heure_debut), CONCAT(ch.date_jour, ' ', ch.heure_fin)) ELSE 0 END), 0) AS minutes_restantes,
    pa.statut
FROM pta_annuel pa
JOIN agent a ON a.id_agent = pa.id_agent
LEFT JOIN poste_agent po ON po.id_poste = a.id_poste
LEFT JOIN planning p ON p.id_agent = pa.id_agent
LEFT JOIN creneau_horaire ch ON ch.id_planning = p.id_planning AND ch.date_jour BETWEEN pa.date_debut AND pa.date_fin
LEFT JOIN motif_planning mp ON mp.id_motif = ch.id_motif
GROUP BY pa.id_pta, pa.id_agent, a.matricule, a.nom, a.prenom, po.code, po.libelle,
         a.type_contrat, pa.date_debut, pa.date_fin, pa.quotite_travail,
         pa.quota_cible_minutes, pa.statut;

CREATE OR REPLACE VIEW v_equipe_pta_controle AS
SELECT
    e.id_equipe,
    e.libelle,
    e.type_equipe,
    e.id_structure,
    s.nom AS structure_nom,
    e.date_debut,
    e.date_fin,
    e.nombre_enfants_moins_6,
    e.nombre_enfants_6_plus,
    GREATEST(
        e.minimum_agents,
        CEIL(e.nombre_enfants_moins_6 / e.ratio_moins_6) + CEIL(e.nombre_enfants_6_plus / e.ratio_6_plus)
    ) AS agents_requis,
    COUNT(em.id_agent) AS agents_affectes,
    SUM(CASE WHEN a.est_diplome = TRUE THEN 1 ELSE 0 END) AS agents_diplomes,
    CASE WHEN COUNT(em.id_agent) = 0 THEN 0
         ELSE ROUND(100 * SUM(CASE WHEN a.est_diplome = TRUE THEN 1 ELSE 0 END) / COUNT(em.id_agent), 2)
    END AS pourcentage_diplomes,
    e.pourcentage_diplomes_min,
    SUM(CASE WHEN em.fonction_equipe = 'RESPONSABLE' THEN 1 ELSE 0 END) AS responsables,
    e.statut
FROM equipe_pta e
JOIN structure s ON s.id_structure = e.id_structure
LEFT JOIN equipe_pta_membre em ON em.id_equipe = e.id_equipe
LEFT JOIN agent a ON a.id_agent = em.id_agent
GROUP BY e.id_equipe, e.libelle, e.type_equipe, e.id_structure, s.nom,
         e.date_debut, e.date_fin, e.nombre_enfants_moins_6, e.nombre_enfants_6_plus,
         e.ratio_moins_6, e.ratio_6_plus, e.minimum_agents,
         e.pourcentage_diplomes_min, e.statut;

COMMIT;
