"""design.json schema produced by the Solution Architect."""

from __future__ import annotations

from typing import List, Optional

from pydantic import BaseModel, Field

# Align with docs/phase-0/ALLOWLIST.md
V1_ALLOWLIST = frozenset(
    {
        "CustomField",
        "ValidationRule",
        "Flow",  # record-triggered only in v1 notes
        "ApexClass",
        "ApexTrigger",
        "LightningComponentBundle",
        "PermissionSet",
    }
)

# Common aliases → canonical Metadata API names
_TYPE_ALIASES = {
    "customfield": "CustomField",
    "custom_field": "CustomField",
    "field": "CustomField",
    "validationrule": "ValidationRule",
    "validation_rule": "ValidationRule",
    "flow": "Flow",
    "apexclass": "ApexClass",
    "apex": "ApexClass",
    "apextrigger": "ApexTrigger",
    "trigger": "ApexTrigger",
    "lightningcomponentbundle": "LightningComponentBundle",
    "lwc": "LightningComponentBundle",
    "lightningcomponent": "LightningComponentBundle",
    "permissionset": "PermissionSet",
    "permission_set": "PermissionSet",
}

DESTRUCTIVE_ACTIONS = frozenset({"delete", "destroy", "remove"})

DESIGN_REVIEW_COMMENT_PREFIX = "Agent Nova design ready for review"


def normalize_metadata_type(raw: str) -> str:
    key = (raw or "").strip()
    if not key:
        return key
    aliased = _TYPE_ALIASES.get(key.lower().replace(" ", ""))
    if aliased:
        return aliased
    for allowed in V1_ALLOWLIST:
        if key.lower() == allowed.lower():
            return allowed
    return key


class MetadataPlanItem(BaseModel):
    metadata_type: str
    api_name: str
    action: str = Field(description="create | update")
    object: Optional[str] = None
    notes: Optional[str] = None


class DesignArtifact(BaseModel):
    jira_key: str
    summary: str
    approach: str
    metadata_plan: List[MetadataPlanItem] = Field(default_factory=list)
    dependencies: List[str] = Field(default_factory=list)
    risks_or_escalations: List[str] = Field(default_factory=list)
    out_of_allowlist: bool = False
    confidence: float = Field(ge=0.0, le=1.0, default=0.7)
    notes: Optional[str] = None

    def design_review_comment_body(self) -> str:
        lines = [
            f"## {DESIGN_REVIEW_COMMENT_PREFIX}",
            "",
            f"Summary: {self.summary}",
            f"Approach: {self.approach}",
            "",
            "Metadata plan:",
        ]
        if self.metadata_plan:
            for i, item in enumerate(self.metadata_plan, start=1):
                obj = f" on {item.object}" if item.object else ""
                note = f" — {item.notes}" if item.notes else ""
                lines.append(
                    f"{i}. {item.metadata_type} {item.api_name} ({item.action}){obj}{note}"
                )
        else:
            lines.append("- (empty)")
        if self.risks_or_escalations:
            lines.extend(["", "Risks / escalations:"])
            for r in self.risks_or_escalations:
                lines.append(f"- {r}")
        if self.out_of_allowlist:
            lines.extend(
                [
                    "",
                    "Note: This design flagged out-of-allowlist items. Review carefully before approving.",
                ]
            )
        lines.extend(
            [
                "",
                "Next step: reply with approve to continue, or reject to request design changes.",
            ]
        )
        return "\n".join(lines)


def enforce_allowlist(design: DesignArtifact) -> DesignArtifact:
    """Keep only allowlisted create/update items; escalate blocked/destructive."""
    allowed: list[MetadataPlanItem] = []
    risks = list(design.risks_or_escalations)
    blocked_any = False

    for item in design.metadata_plan:
        normalized_type = normalize_metadata_type(item.metadata_type)
        action = (item.action or "create").strip().lower()
        if action in DESTRUCTIVE_ACTIONS:
            blocked_any = True
            msg = (
                f"Destructive action '{action}' on {normalized_type}/{item.api_name} "
                "is outside v1 scope — escalate"
            )
            if msg not in risks:
                risks.append(msg)
            continue
        if normalized_type not in V1_ALLOWLIST:
            blocked_any = True
            msg = f"Metadata type outside v1 allowlist: {normalized_type}"
            if msg not in risks:
                risks.append(msg)
            continue
        allowed.append(
            item.model_copy(update={"metadata_type": normalized_type, "action": action})
        )

    return design.model_copy(
        update={
            "metadata_plan": allowed,
            "risks_or_escalations": risks,
            "out_of_allowlist": design.out_of_allowlist or blocked_any,
        }
    )
