"""
scripts/validate.py
Valide le fichier de motifs livre (tex/hyph-mg.tex) contre :
  1. l'integrite des clusters proteges (source de verite = le fichier .tex)
  2. la synchronisation avec le corpus source + les overrides manuels
  3. les contradictions entre overrides et motifs regeneres
  4. la couverture du corpus (avertissement, pas bloquant)
  5. la justification des overrides (avertissement)
"""

from __future__ import annotations

import argparse
import re
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from source.generate_patterns import (
    AnnotatedWord,
    MalagasyPhonotactics,
    PatternExtractor,
    find_override_contradictions,
    load_annotated_words,
    load_manual_overrides,
)


class ValidationReport:
    def __init__(self) -> None:
        self.errors: list[str] = []
        self.warnings: list[str] = []

    def error(self, msg: str) -> None:
        self.errors.append(msg)

    def warn(self, msg: str) -> None:
        self.warnings.append(msg)

    def ok(self) -> bool:
        return not self.errors

    def render_text(self) -> str:
        lines = [f"[AVERTISSEMENT] {w}" for w in self.warnings]
        lines += [f"[ERREUR] {e}" for e in self.errors]
        status = "OK" if self.ok() else "ECHEC"
        lines.append(
            f"\nValidation : {status} "
            f"({len(self.errors)} erreur(s), {len(self.warnings)} avertissement(s))"
        )
        return "\n".join(lines)

    def render_markdown(self) -> str:
        status = "OK" if self.ok() else "ECHEC"
        lines = [f"# Rapport de validation -- hyph-malagasy\n", f"**Statut : {status}**\n"]
        if self.errors:
            lines.append("## Erreurs\n")
            lines += [f"- {e}" for e in self.errors]
        if self.warnings:
            lines.append("\n## Avertissements\n")
            lines += [f"- {w}" for w in self.warnings]
        return "\n".join(lines)


def parse_tex_patterns(tex_path: Path) -> list[str]:
    text = tex_path.read_text(encoding="utf-8")
    match = re.search(r"\\patterns\{%?\s*(.*?)\}", text, re.DOTALL)
    if not match:
        raise ValueError(f"Aucun bloc \\patterns{{...}} trouve dans {tex_path}")
    body = match.group(1)
    return [line.strip() for line in body.splitlines() if line.strip() and line.strip() != "%"]


def check_cluster_integrity(patterns: list[str], phonotactics: MalagasyPhonotactics, report: ValidationReport) -> None:
    for pattern in patterns:
        for v in phonotactics.find_violations(pattern):
            report.error(f"tex/hyph-mg.tex : motif '{v.pattern}' scinde le cluster protege '{v.cluster}'")


def check_sync_with_corpus(
    tex_patterns: list[str], regenerated_patterns: list[str], manual_overrides: list[str], report: ValidationReport
) -> None:
    tex_set = set(tex_patterns)
    expected_set = set(regenerated_patterns) | set(manual_overrides)
    missing_from_tex = expected_set - tex_set
    unexplained_in_tex = tex_set - expected_set
    if missing_from_tex:
        report.error(
            f"{len(missing_from_tex)} motif(s) attendu(s) absent(s) de tex/hyph-mg.tex "
            f"(regeneration requise) : {sorted(missing_from_tex)[:5]}..."
        )
    if unexplained_in_tex:
        report.error(
            f"{len(unexplained_in_tex)} motif(s) dans tex/hyph-mg.tex ne proviennent ni du "
            f"corpus ni de source/manual-overrides.txt : {sorted(unexplained_in_tex)[:5]}..."
        )


def check_override_contradictions(manual_overrides: list[str], regenerated_patterns: list[str], report: ValidationReport) -> None:
    for c in find_override_contradictions(manual_overrides, regenerated_patterns):
        report.error(
            f"contradiction : l'override '{c.override_pattern}' indique une coupure de "
            f"parite opposee au motif du corpus '{c.corpus_pattern}' en position {c.position} "
            f"({c.override_value} vs {c.corpus_value})"
        )


def check_corpus_coverage(words: list[AnnotatedWord], kept_rules, report: ValidationReport) -> None:
    covered = {w for rule in kept_rules for w in rule.source_words}
    for word in words:
        if word.raw not in covered:
            report.warn(f"aucun motif retenu pour '{word.raw}' -- verifier min_len/max_len")


def check_overrides_have_justification(overrides_path: Path, report: ValidationReport) -> None:
    if not overrides_path.exists():
        return
    for line in overrides_path.read_text(encoding="utf-8").splitlines():
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        pattern_part, _, comment_part = stripped.partition("#")
        if not comment_part.strip():
            report.warn(f"override '{pattern_part.strip()}' sans reference de ticket/issue explicite")


def validate(corpus_path: Path, tex_path: Path, overrides_path: Path) -> ValidationReport:
    report = ValidationReport()
    words = load_annotated_words(corpus_path)

    extractor = PatternExtractor(min_len=2, max_len=6)
    for w in words:
        extractor.add_word(w)

    phonotactics = MalagasyPhonotactics()
    all_rules = extractor.patterns()
    kept_rules = phonotactics.force_cluster_integrity(all_rules)
    regenerated_patterns = [r.pattern for r in kept_rules]
    manual_overrides = load_manual_overrides(overrides_path)

    try:
        tex_patterns = parse_tex_patterns(tex_path)
    except (FileNotFoundError, ValueError) as e:
        report.error(str(e))
        return report

    check_cluster_integrity(tex_patterns, phonotactics, report)
    check_sync_with_corpus(tex_patterns, regenerated_patterns, manual_overrides, report)
    check_override_contradictions(manual_overrides, regenerated_patterns, report)
    check_corpus_coverage(words, kept_rules, report)
    check_overrides_have_justification(overrides_path, report)

    return report


def main() -> int:
    parser = argparse.ArgumentParser(description="Valide les motifs de cesure malgache")
    parser.add_argument("--corpus", type=Path, default=Path("source/malagasy-hyphenation.txt"))
    parser.add_argument("--tex", type=Path, default=Path("tex/hyph-mg.tex"))
    parser.add_argument("--overrides", type=Path, default=Path("source/manual-overrides.txt"))
    parser.add_argument("--format", choices=["text", "markdown"], default="text")
    args = parser.parse_args()

    report = validate(args.corpus, args.tex, args.overrides)
    print(report.render_markdown() if args.format == "markdown" else report.render_text())
    return 0 if report.ok() else 1


if __name__ == "__main__":
    sys.exit(main())
