"""Lecture des listes de notes en fin de rapport de dimension.

Cinq dimensions (dim06, dim08, dim09, dim11, dim12) ne portent pas — ou peu —
de blocs sourcés : leurs références vivent dans une liste finale du type ::

    [^1141^] senat.fr — Texte n° 890, projet de loi cohésion républicaine
             (09/07/2026) — https://www.senat.fr/leg/pjl25-890.html
    [^44^]   diplomatie.gouv.fr, 16/04/2026.

Toutes ne portent pas d'URL : sur les 258 notes du corpus, 150 en sont
dépourvues. Deux cas sont alors distingués :

- la note cite un identifiant Légifrance (``JORFTEXT…``, ``JORFARTI…``) : l'URL
  canonique est reconstruite, ce qui n'invente rien puisque le schéma d'URL est
  fixe et documenté ;
- sinon la référence est conservée telle quelle, sans URL, et comptée comme
  « non résolue » dans le compte-rendu d'import. Elle pourra être rapprochée de
  la bibliographie consolidée, qui, elle, est intégralement liée.
"""

from __future__ import annotations

import re
from dataclasses import dataclass
from datetime import date

from pipeline.modeles import Confiance, Source
from pipeline.parseurs.dates_fr import lire_date
from pipeline.parseurs.markdown import nettoyer

ANNEE_CORPUS = 2026

_LIGNE_NOTE = re.compile(r"^\[\^([0-9.]+)\^\]\s+(.*)$")
_URL = re.compile(r"https?://[^\s;,)\]]+")
_IDENTIFIANT_LEGIFRANCE = re.compile(r"\b(JORFTEXT\d{12}|JORFARTI\d{12}|LEGITEXT\d{12})\b")
_DATE_PARENTHESES = re.compile(r"\(([^)]*\d{4}[^)]*)\)")

# Schéma d'URL documenté de Légifrance : un identifiant JORF s'ouvre toujours à
# cette adresse. Reconstruire le lien n'ajoute aucune information nouvelle.
_GABARIT_LEGIFRANCE = "https://www.legifrance.gouv.fr/jorf/id/{identifiant}"


@dataclass(slots=True)
class Note:
    """Une référence numérotée en fin de rapport de dimension."""

    dimension: str
    numero: str
    texte: str
    url: str | None = None
    editeur: str | None = None
    date_publication: date | None = None
    url_reconstruite: bool = False

    @property
    def marqueur(self) -> str:
        return f"{self.dimension}-{self.numero}"

    def en_source(self) -> Source | None:
        """Convertit la note en source, ou `None` si elle n'a pas d'URL."""
        if not self.url:
            return None
        return Source(
            url=self.url,
            titre=self.texte[:280] or None,
            editeur=self.editeur,
            date_publication=self.date_publication,
            confiance=Confiance.MEDIUM,
            marqueur=self.marqueur,
            fichier_origine=f"research/lois-2026_{self.dimension}.md",
        )


def parser(markdown: str, dimension: str) -> list[Note]:
    """Extrait toutes les notes numérotées d'un rapport de dimension."""
    notes: list[Note] = []

    for ligne in markdown.splitlines():
        correspondance = _LIGNE_NOTE.match(ligne.strip())
        if not correspondance:
            continue
        notes.append(_lire_note(correspondance.group(1), correspondance.group(2), dimension))

    return notes


def _lire_note(numero: str, corps: str, dimension: str) -> Note:
    url: str | None = None
    reconstruite = False

    if trouvee := _URL.search(corps):
        url = trouvee.group(0).rstrip(".,;)")
    elif identifiant := _IDENTIFIANT_LEGIFRANCE.search(corps):
        url = _GABARIT_LEGIFRANCE.format(identifiant=identifiant.group(1))
        reconstruite = True

    return Note(
        dimension=dimension,
        numero=numero,
        texte=nettoyer(_sans_url(corps)),
        url=url,
        editeur=_lire_editeur(corps),
        date_publication=_lire_date_note(corps),
        url_reconstruite=reconstruite,
    )


def _sans_url(corps: str) -> str:
    return _URL.sub("", corps).strip(" —–-:.,")


def _lire_editeur(corps: str) -> str | None:
    """L'éditeur ouvre la note, avant le tiret cadratin ou la première virgule."""
    debut = _sans_url(corps)
    for separateur in ("—", "–", " : ", ","):
        if separateur in debut:
            debut = debut.split(separateur, 1)[0]
            break
    debut = nettoyer(debut).strip(" .")
    return debut[:120] or None


def _lire_date_note(corps: str) -> date | None:
    """Date entre parenthèses en priorité, sinon première date du corps."""
    for parenthese in _DATE_PARENTHESES.findall(corps):
        if lue := lire_date(parenthese, annee_defaut=ANNEE_CORPUS):
            return lue
    return lire_date(_sans_url(corps), annee_defaut=ANNEE_CORPUS)
