"""Company Intelligence engine (Phase 2A) — build the Company Capability Profile.

Deterministic, no LLM/RAG. Turns a raw CompanyContext into capability evidence,
candidates and (only via explicit verification) confirmed capabilities.

HARD RULE enforced here: a certification yields at most an INFERRED candidate; it
can NEVER produce a CONFIRMED capability on its own. Only real ExistingEvidence
(`proves_capability_id`) promotes a capability to CONFIRMED. Certifications without
a known mapping yield evidence-of-claim but NO inferred capability (the mapping is
Execution's data, injected — never hard-coded here).

Python 3.9 compatible (no `|` unions).
"""

from __future__ import annotations

from typing import Dict, List, Optional, Tuple

from compliance.reasoning.enums import Confidence

from .contract import EMPTY_MAPPING, CertificationCapabilityMap
from .schemas import (
    CapabilityEvidence,
    CompanyCapabilityProfile,
    CompanyContext,
    OperationalCapability,
    OperationalCapabilityCandidate,
    VerificationStatus,
)


def _declared(context: CompanyContext) -> List[OperationalCapabilityCandidate]:
    out: List[OperationalCapabilityCandidate] = []
    for d in context.declarations:
        out.append(
            OperationalCapabilityCandidate(
                capability_id=d.capability_id,
                source="declaration:%s" % context.company_id,
                confidence=Confidence.MEDIUM,
                verification_status=VerificationStatus.DECLARED,
            )
        )
    return out


def _from_certifications(
    context: CompanyContext, mapping: CertificationCapabilityMap
) -> Tuple[List[CapabilityEvidence], List[OperationalCapabilityCandidate]]:
    # refinement 1: certification -> evidence-of-capability (claim) -> inferred candidate
    evidence: List[CapabilityEvidence] = []
    inferred: List[OperationalCapabilityCandidate] = []
    for cert in context.certifications:
        source = "certification:%s" % cert.certification_id
        evidence.append(
            CapabilityEvidence(
                source=source,
                claim="Company holds %s" % (cert.name or cert.certification_id),
                certification_id=cert.certification_id,
            )
        )
        entry = mapping.get(cert.certification_id)
        if entry is None:
            continue  # no mapping known -> NO inferred capability (data is Execution's)
        for cap_id in entry.capability_ids:
            inferred.append(
                OperationalCapabilityCandidate(
                    capability_id=cap_id,
                    source=source,
                    confidence=entry.confidence,
                    verification_status=VerificationStatus.INFERRED,
                )
            )
    return evidence, inferred


def _confirmed_from_evidence(context: CompanyContext) -> List[OperationalCapability]:
    proven: Dict[str, List[str]] = {}
    for ev in context.evidence:
        cap = ev.proves_capability_id
        if not cap:
            continue
        proven.setdefault(cap, []).append(ev.evidence_id)
    return [
        OperationalCapability(
            capability_id=cap,
            verification_status=VerificationStatus.CONFIRMED,
            confidence=Confidence.HIGH,
            sources=sources,
        )
        for cap, sources in proven.items()
    ]


def build_company_profile(
    context: CompanyContext, mapping: Optional[CertificationCapabilityMap] = None
) -> CompanyCapabilityProfile:
    """Build the Company Capability Profile from raw context + an injected mapping.

    `mapping` defaults to EMPTY (no inferred candidates) so that the cert->capability
    table can only ever come from the Compliance Execution domain.
    """
    mapping = EMPTY_MAPPING if mapping is None else mapping
    evidence, inferred = _from_certifications(context, mapping)
    declared = _declared(context)
    confirmed = _confirmed_from_evidence(context)
    confirmed_ids = {oc.capability_id for oc in confirmed}
    # a confirmed capability is no longer a mere candidate
    candidates = [c for c in (declared + inferred) if c.capability_id not in confirmed_ids]
    return CompanyCapabilityProfile(
        company_id=context.company_id,
        capability_evidence=evidence,
        candidate_capabilities=candidates,
        confirmed_capabilities=confirmed,
    )
