-- Backfill #103 : attribuer un numero_dossier aux entrées existantes (NULL)
-- Famille = lien co_parent OU partage d'au moins un enfant (même dossier).
-- Ordre : par année, AM puis familles (une entrée par famille), séquence 000001, 000002...
-- À exécuter après 2026_numero_dossier.sql

DO $$
DECLARE
  yr INT;
  seq INT;
  num TEXT;
  r RECORD;
  family_user_ids UUID[];
BEGIN
  -- Réinitialiser pour rejouer le backfill (cohérence AM + familles)
  UPDATE parents SET numero_dossier = NULL;
  UPDATE utilisateurs SET numero_dossier = NULL
    WHERE role IN ('parent', 'assistante_maternelle');
  UPDATE assistantes_maternelles SET numero_dossier = NULL;

  FOR yr IN
    SELECT DISTINCT EXTRACT(YEAR FROM u.cree_le)::INT
    FROM utilisateurs u
    WHERE (
      (u.role = 'assistante_maternelle' AND u.numero_dossier IS NULL)
      OR EXISTS (SELECT 1 FROM parents p WHERE p.id_utilisateur = u.id AND p.numero_dossier IS NULL)
    )
    ORDER BY 1
  LOOP
    seq := 0;

    -- 1) AM : par ordre de création
    FOR r IN
      SELECT u.id
      FROM utilisateurs u
      WHERE u.role = 'assistante_maternelle'
        AND u.numero_dossier IS NULL
        AND EXTRACT(YEAR FROM u.cree_le) = yr
      ORDER BY u.cree_le
    LOOP
      seq := seq + 1;
      num := yr || '-' || LPAD(seq::TEXT, 6, '0');
      UPDATE utilisateurs SET numero_dossier = num WHERE id = r.id;
      UPDATE assistantes_maternelles SET numero_dossier = num WHERE id_utilisateur = r.id;
    END LOOP;

    -- 2) Familles : une entrée par "dossier" (co_parent OU enfants partagés)
    -- family_rep = min(id) de la composante connexe (lien co_parent + partage d'enfants)
    FOR r IN
      WITH RECURSIVE
      links AS (
        SELECT p.id_utilisateur AS p1, p.id_co_parent AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
        UNION ALL
        SELECT p.id_co_parent AS p1, p.id_utilisateur AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
        UNION ALL
        SELECT ep1.id_parent AS p1, ep2.id_parent AS p2
        FROM enfants_parents ep1
        JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
        UNION ALL
        SELECT ep2.id_parent AS p1, ep1.id_parent AS p2
        FROM enfants_parents ep1
        JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
      ),
      rec AS (
        SELECT id_utilisateur AS id, id_utilisateur AS rep FROM parents
        UNION
        SELECT l.p2 AS id, LEAST(rec_alias.rep, l.p2) AS rep FROM links l JOIN rec rec_alias ON rec_alias.id = l.p1
      ),
      family_rep AS (
        SELECT id, MIN(rep::text)::uuid AS rep FROM rec GROUP BY id
      ),
      fam_ordered AS (
        SELECT fr.rep AS family_rep, MIN(u.cree_le) AS cree_le
        FROM family_rep fr
        JOIN parents p ON p.id_utilisateur = fr.id
        JOIN utilisateurs u ON u.id = p.id_utilisateur
        WHERE p.numero_dossier IS NULL
          AND EXTRACT(YEAR FROM u.cree_le) = yr
        GROUP BY fr.rep
        ORDER BY MIN(u.cree_le)
      )
      SELECT fo.family_rep
      FROM fam_ordered fo
    LOOP
      seq := seq + 1;
      num := yr || '-' || LPAD(seq::TEXT, 6, '0');

      WITH RECURSIVE
      links AS (
        SELECT p.id_utilisateur AS p1, p.id_co_parent AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
        UNION ALL
        SELECT p.id_co_parent AS p1, p.id_utilisateur AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
        UNION ALL
        SELECT ep1.id_parent AS p1, ep2.id_parent AS p2
        FROM enfants_parents ep1
        JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
        UNION ALL
        SELECT ep2.id_parent AS p1, ep1.id_parent AS p2
        FROM enfants_parents ep1
        JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
      ),
      rec AS (
        SELECT id_utilisateur AS id, id_utilisateur AS rep FROM parents
        UNION
        SELECT l.p2 AS id, LEAST(rec_alias.rep, l.p2) AS rep FROM links l JOIN rec rec_alias ON rec_alias.id = l.p1
      ),
      family_rep AS (
        SELECT id, MIN(rep::text)::uuid AS rep FROM rec GROUP BY id
      )
      SELECT array_agg(DISTINCT fr.id) INTO family_user_ids
      FROM family_rep fr
      WHERE fr.rep = r.family_rep;

      UPDATE utilisateurs SET numero_dossier = num WHERE id = ANY(family_user_ids);
      UPDATE parents SET numero_dossier = num WHERE id_utilisateur = ANY(family_user_ids);
    END LOOP;

    INSERT INTO numero_dossier_sequence (annee, prochain)
    VALUES (yr, seq + 1)
    ON CONFLICT (annee) DO UPDATE
    SET prochain = GREATEST(numero_dossier_sequence.prochain, seq + 1);
  END LOOP;
END $$;
