"""CanonicalProductRegulatoryProfile -> reasoning ProductProfile (adapter/DTO).

The reasoning engine stays the consumer, never the source of truth (spec): the
canonical leads, this projects it into the Python reasoning ProductProfile so the
Reasoning engine and the Go gap engine run off ONE semantic profile (acceptance
#10). AI classification is NOT done here — only `uses_ai` is forwarded; risk
classification stays delegated to ai-act/ucca (acceptance #3).

This is the ONLY one-way coupling profile -> reasoning; reasoning never imports
profile, so the reasoning layer stays hermetic.
"""

from __future__ import annotations

from typing import List, Optional

from compliance.reasoning.enums import ManufacturerRole, MarketModel, ProductLifecyclePhase
from compliance.reasoning.schemas import ProductProfile

from .canonical import CanonicalProductRegulatoryProfile, CanonicalProductType

_SOFTWARE_TYPES = {CanonicalProductType.SOFTWARE, CanonicalProductType.SAAS, CanonicalProductType.IOT}
_SOFTWARE_TECH = {"ai", "api", "database", "encryption", "ota_updates", "cloud", "blockchain"}
_EU_HINTS = {"DE", "AT", "FR", "IT", "NL", "LU", "LI", "EU", "EWR", "EEA", "DACH"}
_B2X = {"B2B": MarketModel.B2B, "B2C": MarketModel.B2C, "B2B_B2C": MarketModel.BOTH, "B2B2C": MarketModel.BOTH}


def _or_none(*values: Optional[bool]) -> Optional[bool]:
    """True if any value is truthy; None if all are None/absent; else False."""
    if any(v is True for v in values):
        return True
    if all(v is None for v in values):
        return None
    return False


def _has_software(c: CanonicalProductRegulatoryProfile) -> Optional[bool]:
    type_sig = True if c.product_type in _SOFTWARE_TYPES else None
    tech_sig = True if (set(c.technologies) & _SOFTWARE_TECH) else None
    return _or_none(c.has_embedded_software, c.has_software_updates, c.uses_ai, type_sig, tech_sig)


def _eu_market(markets: List[str]) -> Optional[bool]:
    if not markets:
        return None
    return True if (set(markets) & _EU_HINTS) else False


def _has_radio(c: CanonicalProductRegulatoryProfile) -> Optional[bool]:
    if c.has_radio_module is not None:
        return c.has_radio_module
    if any(comp.kind.value == "radio_module" for comp in c.components):
        return True
    return None


def to_reasoning_profile(c: CanonicalProductRegulatoryProfile) -> ProductProfile:
    role = ManufacturerRole(c.economic_operator_role.value) if c.economic_operator_role else None
    phase = ProductLifecyclePhase(c.lifecycle_phase.value) if c.lifecycle_phase else None
    b2x = _B2X.get(c.b2b_or_b2c) if c.b2b_or_b2c else None
    is_machine = c.is_machine if c.is_machine is not None else (
        True if c.product_type == CanonicalProductType.MACHINERY else None
    )
    generates_data = c.generates_usage_data if c.generates_usage_data is not None else (
        True if "telemetry" in c.data_processing else None
    )
    return ProductProfile(
        product_name=c.name or "Produkt",
        product_profile_id=c.product_profile_id,
        manufacturer_role=role,
        product_type=[c.product_type.value] if c.product_type else [],
        has_software=_has_software(c),
        has_embedded_software=c.has_embedded_software,
        has_remote_access=c.has_remote_access,
        has_cloud_connection=True if "cloud" in c.technologies else None,
        has_ai_functionality=c.uses_ai,
        has_radio_module=_has_radio(c),
        has_safety_function=c.has_safety_function,
        generates_usage_data=generates_data,
        is_machine=is_machine,
        is_component=c.is_component,
        is_spare_part=c.is_spare_part,
        eu_market=_eu_market(c.markets),
        b2b_or_b2c=b2x,
        lifecycle_phase=phase,
        company_size=c.company_size,
        sector=c.sector_industry,
    )
