"""Pydantic v2 models for framework profiles, controls, and mappings.

All models use strict mode. YAML files are validated into these models
at load time via model_validate().
"""

from __future__ import annotations

from typing import Any

from pydantic import BaseModel, ConfigDict

# -------------------------------------------------------------------
# Framework registry models
# -------------------------------------------------------------------


class FrameworkMeta(BaseModel):
    """Single framework entry in the registry."""

    model_config = ConfigDict(strict=True)

    id: str
    name: str
    version: str
    authority: str
    tier: str  # "community", "pro", "team", "agency", "enterprise"
    cloud: str  # "all", "gcp", "aws", "azure"
    category: str  # "global", "regional", "industry", "cis"
    control_count: int
    description: str = ""
    url: str = ""


class FrameworkRegistry(BaseModel):
    """Top-level framework_registry.yaml model."""

    model_config = ConfigDict(strict=True)

    schema_version: int
    frameworks: list[FrameworkMeta]


# -------------------------------------------------------------------
# Control models
# -------------------------------------------------------------------


class Control(BaseModel):
    """Single compliance control."""

    model_config = ConfigDict(strict=True)

    id: str
    title: str
    description: str = ""
    severity: str = "medium"  # "critical", "high", "medium", "low", "info"
    section: str = ""
    family: str = ""


class ControlsFile(BaseModel):
    """Top-level controls YAML for a framework."""

    model_config = ConfigDict(strict=True)

    schema_version: int
    framework_id: str
    framework_version: str
    controls: list[Control]


# -------------------------------------------------------------------
# Check models (evaluation operators for resource attributes)
# -------------------------------------------------------------------


class Check(BaseModel):
    """Single automatable check against a resource attribute."""

    model_config = ConfigDict(strict=True)

    operator: str  # equals|not_equals|not_empty|exists|in_list|gte|lte|regex_match
    attribute: str  # dot-separated path: "settings.0.ip_configuration.0.ssl_mode"
    expected: Any = None
    failure_message: str = ""
    auto_fix_safe: bool = False
    from_check: str | None = None


class Dependency(BaseModel):
    """Supporting resource required by a remediation patch."""

    model_config = ConfigDict(strict=True)

    resource_type: str
    template: str
    risk_level: str = "low"  # "low" | "medium" | "high"


# -------------------------------------------------------------------
# Mapping models
# -------------------------------------------------------------------


class ResourceMapping(BaseModel):
    """Maps a Checkov check to a framework control for a specific cloud."""

    model_config = ConfigDict(strict=True)

    check_id: str
    control_id: str
    resource_types: list[str] = []
    native_id: str = ""
    enforcement_tier: str = "runtime"
    confidence: str = "high"  # "verified", "high", "medium", "low"
    checks: list[Check] = []
    required_config: dict[str, Any] | None = None
    dependencies: list[Dependency] = []
    requirement_id: str | None = None
    resource_category: str = ""


class MappingFile(BaseModel):
    """Top-level mapping YAML (per framework + cloud)."""

    model_config = ConfigDict(strict=True)

    schema_version: int
    framework_id: str
    cloud: str
    provider: str = ""
    min_provider_version: str | None = None
    mappings: list[ResourceMapping]


# -------------------------------------------------------------------
# Cross-mapping models
# -------------------------------------------------------------------


class ControlCrossMapping(BaseModel):
    """Cross-reference between controls of two frameworks."""

    model_config = ConfigDict(strict=True)

    source_framework: str
    source_control: str
    target_framework: str
    target_control: str
    relationship: str = "equivalent"  # "equivalent", "parent", "overlaps"


class CrossMappingIndex(BaseModel):
    """Top-level cross_mappings/index.yaml model."""

    model_config = ConfigDict(strict=True)

    schema_version: int
    mappings: list[ControlCrossMapping]


# -------------------------------------------------------------------
# Not-applicable resource types
# -------------------------------------------------------------------


class NotApplicableEntry(BaseModel):
    """Resource types not applicable to a specific cloud."""

    model_config = ConfigDict(strict=True)

    cloud: str
    resource_types: list[str]


class NotApplicableFile(BaseModel):
    """Top-level not_applicable.yaml model."""

    model_config = ConfigDict(strict=True)

    schema_version: int
    entries: list[NotApplicableEntry]
