#!/usr/bin/env python3
"""Conservative preflight check for Aibility campaign drafts."""

from __future__ import annotations

import json
import re
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parent
CONFIG_PATH = ROOT / "engine-config.json"
NUMBER_RE = re.compile(
    r"(?<!\w)(?:\d{1,3}(?:[ \u00a0]\d{3})+|\d+)(?:[.,]\d+)?(?:\s?(?:%|\+))?"
)
URL_RE = re.compile(r"https?://\S+")
HASHTAG_RE = re.compile(r"(?<!\w)#[\wá-žÁ-Ž]+", re.UNICODE)


def normalize_number(value: str) -> str:
    return value.replace("\u00a0", "").replace(" ", "").replace(",", ".").lower()


def load_config() -> dict:
    with CONFIG_PATH.open(encoding="utf-8") as handle:
        return json.load(handle)


def allowed_numbers(config: dict) -> set[str]:
    allowed: set[str] = set()
    for claim in config["claims"]:
        for form in claim.get("allowed_number_forms", []):
            for match in NUMBER_RE.findall(form):
                allowed.add(normalize_number(match))
    return allowed


def number_datasets(config: dict) -> dict[str, set[str]]:
    """Ke každému povolenému číslu množina datasetů, ve kterých se vyskytuje."""
    mapping: dict[str, set[str]] = {}
    for claim in config["claims"]:
        dataset = claim.get("dataset")
        if not dataset:
            continue
        for form in claim.get("allowed_number_forms", []):
            for match in NUMBER_RE.findall(form):
                mapping.setdefault(normalize_number(match), set()).add(dataset)
    return mapping


# Slovem zapsaná procenta obcházejí číselný allowlist; hlásíme je jako varování.
NUMBER_WORD_RE = re.compile(
    r"\b(?:(?:dvacet|třicet|čtyřicet|padesát|šedesát|sedmdesát|osmdesát|devadesát)"
    r"(?:\s+(?:jedna|dva|dvě|tři|čtyři|pět|šest|sedm|osm|devět))?"
    r"|jedno|jedna|dva|dvě|tři|čtyři|pět|šest|sedm|osm|devět|deset|sto|sta)"
    r"\s+procent\w*",
    re.IGNORECASE,
)


def validate(text: str, config: dict, link_in_comment: bool = False) -> list[str]:
    issues: list[str] = []
    warnings: list[str] = []
    lowered = text.lower()

    if "—" in text or "–" in text:
        issues.append("Použita dlouhá pomlčka. Nahraď ji znakem '-'.")

    for phrase in config["forbidden_phrases"]:
        if phrase.lower() in lowered:
            issues.append(f"Zakázaná fráze: {phrase!r}.")

    for direction in config["forbidden_directions"]:
        if direction.lower() in lowered:
            issues.append(f"Zakázaný nebo neověřený směr: {direction!r}.")

    hashtags = HASHTAG_RE.findall(text)
    if len(hashtags) > 2:
        issues.append(f"Příliš mnoho hashtagů ({len(hashtags)}): {' '.join(hashtags)}.")

    text_without_urls = URL_RE.sub("", text)
    allowed = allowed_numbers(config)
    datasets_map = number_datasets(config)
    used_datasets: dict[str, list[str]] = {}
    for raw_number in NUMBER_RE.findall(text_without_urls):
        key = normalize_number(raw_number)
        if key not in allowed:
            issues.append(f"Číslo mimo allowlist: {raw_number!r}. Doplň claim nebo číslo odstraň.")
            continue
        claim_datasets = datasets_map.get(key)
        # Jen čísla patřící jednoznačně do jednoho datasetu; produktová čísla
        # (délka Sparku apod.) dataset nemají a míchání nehlídají.
        if claim_datasets and len(claim_datasets) == 1:
            used_datasets.setdefault(next(iter(claim_datasets)), []).append(raw_number)

    if len(used_datasets) > 1:
        detail = "; ".join(
            f"dataset {ds}: {', '.join(nums)}" for ds, nums in sorted(used_datasets.items())
        )
        issues.append(
            f"Smíchané datasety v jednom výstupu ({detail}). "
            "Nejtvrdší pravidlo enginu: vyber jeden dataset a druhý vyhoď."
        )

    for word_match in NUMBER_WORD_RE.findall(text):
        warnings.append(
            f"Procento zapsané slovy: {word_match.strip()!r}. "
            "Allowlist ho neumí zkontrolovat - ověř číslo i dataset ručně."
        )

    cta_url = config["campaign"]["primary_cta_url"]
    cta_count = text.count(cta_url)
    if cta_count == 0:
        if link_in_comment:
            warnings.append(
                "V textu není CTA URL. U organického postu je to záměr, odkaz patří do prvního komentáře."
            )
        else:
            issues.append(f"Chybí primární CTA URL: {cta_url}")
    elif cta_count > config["output_contract"]["max_primary_ctas"]:
        issues.append(f"Primární CTA URL je v textu {cta_count}x; povoleno je 1x.")

    if config["campaign"]["primary_audience"].lower() not in lowered:
        warnings.append(
            "Segment "
            f"{config['campaign']['primary_audience']!r} není v textu pojmenovaný. "
            "U zákaznické copy je to v pořádku, je to interní terminologie."
        )

    return issues, warnings


def main() -> int:
    args = [a for a in sys.argv[1:] if a != "--link-v-komentari"]
    link_in_comment = "--link-v-komentari" in sys.argv[1:]
    if len(args) != 1:
        print("Použití: python3 validate-copy.py cesta-k-draftu.txt [--link-v-komentari]")
        return 2

    draft_path = Path(args[0])
    if not draft_path.exists():
        print(f"Soubor neexistuje: {draft_path}")
        return 2

    config = load_config()
    text = draft_path.read_text(encoding="utf-8")
    issues, warnings = validate(text, config, link_in_comment)

    if issues:
        print("NEPROŠLO")
        for issue in issues:
            print(f"- {issue}")
        for warning in warnings:
            print(f"- poznámka: {warning}")
        return 1

    print("PROŠLO: claimy, CTA a základní anti-slop pravidla jsou v pořádku.")
    for warning in warnings:
        print(f"- poznámka: {warning}")
    print("STATUS: HUMAN_REVIEW_REQUIRED")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
