"""Types for the Maeris Portal API."""

import json
from typing import Any

from pydantic import BaseModel, ConfigDict, Field, field_validator


class FieldPair(BaseModel):
    """Key-value pair for params/headers."""

    model_config = ConfigDict(populate_by_name=True)

    field_name: str = Field(alias="field_name")
    field_value: str = Field(alias="field_value")


class MaerisAPI(BaseModel):
    """Represents an API entry in the Maeris portal."""

    url: str
    type: str  # HTTP method (uppercase)
    name: str
    payload: str = ""
    verification: Any = ""
    params: list[FieldPair] = Field(default_factory=list)
    headers: list[FieldPair] = Field(default_factory=list)
    parent_collection_id: str = ""

    @field_validator("type", mode="before")
    @classmethod
    def _normalise_type(cls, v: Any) -> str:
        """Ensure HTTP method is always uppercase."""
        return str(v).upper() if v else v

    @field_validator("payload", mode="before")
    @classmethod
    def _normalise_payload(cls, v: Any) -> str:
        """Serialize dict payloads to a JSON string with \\r\\n line endings."""
        if isinstance(v, dict):
            return json.dumps(v, indent=2).replace("\n", "\r\n")
        if v is None:
            return ""
        return str(v)



class CreateCollectionRequest(BaseModel):
    """Payload for creating a collection."""

    model_config = ConfigDict(populate_by_name=True)

    name: str
    parent_collection_id: str = Field(default="", alias="parent_collection_id")


class PushResult(BaseModel):
    """Contains the result of pushing APIs to Maeris."""

    model_config = ConfigDict(populate_by_name=True)

    success: bool
    collection_id: str = Field(default="", alias="collection_id")
    collection_name: str = Field(alias="collection_name")
    apis_created: int = Field(default=0, alias="apis_created")
    apis_failed: int = Field(default=0, alias="apis_failed")
    created_api_ids: list[str] = Field(default_factory=list, alias="created_api_ids")
    errors: list[str] = Field(default_factory=list)
    message: str = ""


class MaerisCVSS(BaseModel):
    """CVSS score object for a security finding."""

    score: float = 0.0


class MaerisSecurityScan(BaseModel):
    """Consolidated security scan payload matching Maeris backend schema."""

    model_config = ConfigDict(populate_by_name=True)

    appid: str
    scan_id: str
    run_id: str
    scan_name: str
    scan_intensity: str = "quick"
    status: str = "completed"
    score: int = 0
    grade: str = "F"
    risk_level: str = "high"
    scan_duration: float = 0.0
    enabled_categories: list[str] = Field(default_factory=list)
    created_at: str = ""
    updated_at: str = ""


class MaerisSecurityFinding(BaseModel):
    """Individual security scan finding matching Maeris backend schema."""

    model_config = ConfigDict(populate_by_name=True)

    scan_finding_id: str
    scan_id: str
    run_id: str
    appid: str
    title: str
    description: str
    severity: str = "medium"
    confidence: str = "medium"
    status: str = "active"
    cvss: MaerisCVSS = Field(default_factory=MaerisCVSS)
    cwe: str = ""
    owasp_category: str = ""
    scan_type: str = ""
    testing_category: str = "unknown"
    url: str = ""
    api: str = ""
    evidence: str = ""
    recommendation: str = ""
    impact: float = 0.0
    priority: str = "scheduled"
    # API expects field name "references" in requests.
    reference_links: list[str] = Field(default_factory=list, alias="references")
    occurrences: int = 1
    created_at: str = ""
    updated_at: str = ""


class PortalCollection(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    api_collection_id: str
    name: str
    appid: str | None = None
    top_level: bool | None = None
    parent_collection_id: str | None = None
    created_at: str | None = None


class PortalAPI(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    api_id: str
    collection_id: str
    name: str
    method: str
    url: str
    created_at: str | None = None


class CollectionChildrenEntry(BaseModel):
    """One entry in the batch children response (keyed by collection_id)."""

    model_config = ConfigDict(populate_by_name=True)
    api_collections: list[PortalCollection] = Field(default_factory=list)
    apis: list[PortalAPI] = Field(default_factory=list)
