"""Layer 1: Automated programmatic metrics (no LLM judge).

Pure Python metrics computed from the raw output string.
"""

from __future__ import annotations

import re
from dataclasses import dataclass, field
from typing import Dict

LENS_GROUPS: Dict[str, list[str]] = {
    "Ontoloji": ["ontolog", "entity", "entities", "concept", "hierarchy"],
    "Mereoloji": ["mereolog", "whole-part", "part-whole", "telos", "constituent"],
    "FOL": ["formal logic", "premise", "conclusion", "axiom", "\u2200", "\u2203", "\u2192"],
    "Bayes": ["bayes", "prior", "posterior", "likelihood", "probability", "P("],
    "OyunTeorisi": ["game theor", "equilibri", "payoff", "nash", "strategy", "player"],
    "KategoriTeorisi": ["category theor", "morphism", "functor", "object", "arrow"],
    "Topoloji + Holografik": [
        "topolog", "holograph", "dimension", "fractal", "continuity", "seed"
    ],
}


@dataclass
class Layer1Scores:
    lens_coverage: int  # 0-7: how many lenses substantively mentioned
    section_structure: bool  # has identifiable sections / headers?
    term_precision: int  # count of domain-specific terms used
    citation_density: int  # references to specific parts of input text
    length_ratio: float  # output_length / input_length
    per_lens_detected: Dict[str, bool] = field(default_factory=dict)


def evaluate_layer1(output: str, input_text: str) -> Layer1Scores:
    """Compute all Layer 1 metrics on a single output."""
    output_lower = output.lower()

    # Lens coverage: count lenses with >= 2 keyword hits (avoids false positives)
    per_lens: Dict[str, bool] = {}
    for lens, keywords in LENS_GROUPS.items():
        hits = sum(1 for kw in keywords if kw.lower() in output_lower)
        per_lens[lens] = hits >= 2
    lens_coverage = sum(per_lens.values())

    # Section structure: markdown ## or numbered 1. or **Bold**
    has_sections = bool(
        re.search(r"(^#{1,3}\s|\n#{1,3}\s|\n\d+\.\s|\*\*[A-Z])", output)
    )

    # Term precision: unique domain terms (all lens keywords)
    all_terms = [kw for group in LENS_GROUPS.values() for kw in group]
    term_hits = sum(1 for t in all_terms if t.lower() in output_lower)

    # Citation density: sentences overlapping heavily with input
    input_words = set(input_text.lower().split())
    output_sentences = re.split(r"[.!?]", output)
    citations = 0
    for sent in output_sentences:
        words = sent.lower().split()
        if len(words) >= 3:
            overlap = sum(1 for w in words if w in input_words)
            if overlap / max(len(words), 1) > 0.5:
                citations += 1

    return Layer1Scores(
        lens_coverage=lens_coverage,
        section_structure=has_sections,
        term_precision=term_hits,
        citation_density=citations,
        length_ratio=len(output) / max(len(input_text), 1),
        per_lens_detected=per_lens,
    )
