"""Company Intelligence (Phase 2A) — Company Capability Profile (domain objects).

This is the HEAD of the spine

    Company -> (Operational) Capability -> Product -> Applicable Regulation ->
    Obligation -> Procedure -> Evidence

and answers a DIFFERENT question than Regulatory Intelligence: not "which laws
apply to my product" but "which capabilities does my company already have, and
which regulatory obligations might they already cover".

HARD RULE (structural, not convention): a capability derived from a certification
is at most INFERRED — never CONFIRMED, never "erfuellt". A certification produces
EVIDENCE for a capability, an inference produces a CANDIDATE, and only checked
evidence produces a CONFIRMED capability. This keeps the company side inside
Welt 1 (potential), mirroring `ClaimCoverage` on the obligation side; it is NOT a
conformity verdict (`ComplianceStatus`, Welt 2, owned by Compliance Execution).

OWNERSHIP: Reasoning OWNS this CompanyContext container + the trust-state machine.
It does NOT own the Certification->Capability mapping RULES — those are the same
kind of rule as Feature->Capability and belong to the Compliance Execution
Capability Registry. This layer only CONSUMES `OperationalCapabilityCandidate`
{capability_id, source, confidence, verification_status} via an injected mapping
(see contract.py). No mapping DATA lives in product code (tests inject mocks).

Application/reasoning types, NOT compliance-meta-model classes (architecture
freeze v1.0 untouched). Python 3.9 compatible (no `|` unions).
"""

from __future__ import annotations

from enum import Enum
from typing import List, Optional

from pydantic import BaseModel, Field

from compliance.reasoning.enums import Confidence


class VerificationStatus(str, Enum):
    """Trust state of an operational capability — a FOURTH vocabulary.

    Disjoint from ClaimCoverage (Welt 1, customer claim vs obligation),
    ComplianceStatus (Welt 2, verified conformity) and DeltaType (RCI). It says
    only how well-established a company CAPABILITY is, never whether an obligation
    is met. Progression: DECLARED (customer says) -> INFERRED (a certification
    implies it) -> CONFIRMED (checked against real evidence); UNKNOWN = no signal.
    """

    DECLARED = "declared"
    INFERRED = "inferred"
    CONFIRMED = "confirmed"
    UNKNOWN = "unknown"


# ── raw company inputs (the CompanyContext children) ──────────────────────
class Certification(BaseModel):
    certification_id: str  # e.g. "ISO27001"
    name: str = ""
    scope: str = ""  # what the cert covers, customer-stated


class Declaration(BaseModel):
    """A customer statement that they have a capability ("we do patch management")."""

    capability_id: str
    statement: str = ""


class ExistingProcess(BaseModel):
    process_id: str
    name: str = ""


class ExistingSystem(BaseModel):
    system_id: str
    name: str = ""


class ExistingEvidence(BaseModel):
    """A concrete artefact the company already holds (policy, audit log, SBOM ...).

    `proves_capability_id` is the ONLY thing that may lift a capability to
    CONFIRMED — and only when a human/engine has attached real evidence.
    """

    evidence_id: str
    evidence_type: str = ""  # config_export/test_report/policy/audit_log/...
    proves_capability_id: Optional[str] = None


# ── intermediate: certification -> evidence-of-capability (refinement 1) ──
class CapabilityEvidence(BaseModel):
    """A certification does not yield a capability directly — only EVIDENCE for one.

    "Company holds a certified ISMS" is the evidence/claim; capabilities are then
    INFERRED from it via the injected (Execution-owned) mapping, never directly.
    """

    source: str  # provenance, e.g. "certification:ISO27001"
    claim: str = ""
    certification_id: str = ""


# ── consumed contract type (refinement 2) ─────────────────────────────────
class OperationalCapabilityCandidate(BaseModel):
    """The ONLY thing Reasoning consumes from Execution's capability mapping.

    Named "operational" (organisational ability) to stay distinct from later
    Product/AI/Safety capabilities. A candidate is always Welt 1 — DECLARED or
    INFERRED — and never CONFIRMED on its own.
    """

    capability_id: str
    source: str
    confidence: Confidence = Confidence.MEDIUM
    verification_status: VerificationStatus = VerificationStatus.INFERRED


class OperationalCapability(BaseModel):
    """A capability the company actually has, CONFIRMED against real evidence."""

    capability_id: str
    verification_status: VerificationStatus
    confidence: Confidence = Confidence.MEDIUM
    sources: List[str] = Field(default_factory=list)


# ── the container Reasoning OWNS (raw inputs) ─────────────────────────────
class CompanyContext(BaseModel):
    company_id: str
    certifications: List[Certification] = Field(default_factory=list)
    declarations: List[Declaration] = Field(default_factory=list)
    processes: List[ExistingProcess] = Field(default_factory=list)
    systems: List[ExistingSystem] = Field(default_factory=list)
    evidence: List[ExistingEvidence] = Field(default_factory=list)


# ── derived view (the Company Capability Profile) ─────────────────────────
class CompanyCapabilityProfile(BaseModel):
    """Derived: capability evidence + candidates (declared/inferred) + confirmed.

    `candidate_capabilities` NEVER auto-promote to `confirmed_capabilities`; only
    explicit ExistingEvidence does that. The hard rule is enforced in engine.py.
    """

    company_id: str
    capability_evidence: List[CapabilityEvidence] = Field(default_factory=list)
    candidate_capabilities: List[OperationalCapabilityCandidate] = Field(default_factory=list)
    confirmed_capabilities: List[OperationalCapability] = Field(default_factory=list)
