"""Shared types for obligation scope rules.

`required_evidence` MUST draw from the framework-AGNOSTIC evidence catalog
owned by the Compliance Execution Graph (memory `project_compliance_graph.md`,
User-Direktive 2026-06-25). Do not invent framework-specific evidence types.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import List, Optional

from .enums import AuthorityLevel, Confidence
from .predicates import Condition

# Framework-agnostic shared evidence catalog (the only allowed tokens).
EVIDENCE_CATALOG = frozenset(
    {
        "config_export",
        "test_report",
        "repo_scan",
        "sbom",
        "policy",
        "audit_log",
        "pentest",
        "ticket",
    }
)


@dataclass(frozen=True)
class ObligationRule:
    obligation_id: str
    title: str
    source_regulation: str
    obligation_text: str
    legal_basis_refs: List[str]
    authority_level: AuthorityLevel
    family: str
    applies_if: Condition
    required_capabilities: List[str]
    required_evidence: List[str]
    base_confidence: Confidence = Confidence.HIGH
    applies_unless: Optional[Condition] = None
    lifecycle_phase: List[str] = field(default_factory=list)
    applies_to_role: List[str] = field(default_factory=lambda: ["manufacturer", "importer"])
    overlap_group_id: Optional[str] = None
    # True => obligation_id is owned by the Legal-KG registry (re-link, never re-mint).
    registry_anchor: bool = False
    # True => Machine/Data-Act obligation the registry has not canonicalised yet.
    proposed: bool = False

    def __post_init__(self) -> None:
        bad = [e for e in self.required_evidence if e not in EVIDENCE_CATALOG]
        if bad:
            raise ValueError(
                "obligation %s uses non-catalog evidence %r" % (self.obligation_id, bad)
            )
