"""Routeline — destination matrix + RoutePlanner."""

from __future__ import annotations

import os
from typing import Dict, List, Optional, Tuple

from pydantic import BaseModel, Field

from psyc import log
from psyc.models import Case, IncidentType, TLP


_log = log.get(__name__)


_TLP_RANK: Dict[TLP, int] = {TLP.CLEAR: 0, TLP.GREEN: 1, TLP.AMBER: 2, TLP.RED: 3}

MOCK_CERT_BASE = os.environ.get("PSYC_MOCK_CERT_URL", "http://127.0.0.1:8770")

ENDPOINTS: Dict[str, str] = {
    "CERT-Bund": f"{MOCK_CERT_BASE}/cert-bund/submit",
    "MISP-Community": f"{MOCK_CERT_BASE}/misp/event",
    "URLhaus": f"{MOCK_CERT_BASE}/urlhaus/submit",
    "AbuseIPDB": f"{MOCK_CERT_BASE}/abuseipdb/report",
}


def endpoint_for(destination_name: str) -> Optional[str]:
    return ENDPOINTS.get(destination_name)


class Destination(BaseModel):
    name: str
    kind: str
    max_tlp: TLP
    accepts: List[IncidentType] = Field(default_factory=list)
    priority: int
    payload_kind: str
    countries: List[str] = Field(default_factory=list)
    requires_approval: bool = False


class Route(BaseModel):
    destination_name: str
    priority: int
    payload_kind: str
    max_tlp_allowed: TLP
    requires_approval: bool = False


class BlockedRoute(BaseModel):
    destination_name: str
    reason: str


DESTINATIONS: List[Destination] = [
    Destination(
        name="CERT-Bund",
        kind="authority",
        max_tlp=TLP.RED,
        accepts=[IncidentType.MALWARE, IncidentType.RANSOMWARE, IncidentType.PHISHING, IncidentType.EXPLOIT, IncidentType.BOTNET, IncidentType.DATA_LEAK, IncidentType.CREDENTIAL_LEAK],
        priority=1,
        payload_kind="sealed_evidence_package",
        countries=["DE"],
        requires_approval=True,
    ),
    Destination(
        name="MISP-Community",
        kind="cti_sharing",
        max_tlp=TLP.AMBER,
        accepts=list(IncidentType),
        priority=2,
        payload_kind="stix_indicators",
    ),
    Destination(
        name="URLhaus",
        kind="public_abuse",
        max_tlp=TLP.GREEN,
        accepts=[IncidentType.MALWARE],
        priority=3,
        payload_kind="malware_url_report",
    ),
    Destination(
        name="AbuseIPDB",
        kind="public_abuse",
        max_tlp=TLP.CLEAR,
        accepts=[IncidentType.MALWARE, IncidentType.BOTNET, IncidentType.PHISHING],
        priority=4,
        payload_kind="ip_abuse_report",
    ),
]


def _tlp_allowed(submission_tlp: TLP, dest_max_tlp: TLP) -> bool:
    return _TLP_RANK[submission_tlp] <= _TLP_RANK[dest_max_tlp]


def plan(case: Case) -> Tuple[List[Route], List[BlockedRoute]]:
    routes: List[Route] = []
    blocked: List[BlockedRoute] = []
    for d in DESTINATIONS:
        if not _tlp_allowed(case.classification.tlp, d.max_tlp):
            blocked.append(BlockedRoute(destination_name=d.name, reason="tlp_exceeded"))
            continue
        if case.classification.incident_type is not None and case.classification.incident_type not in d.accepts:
            blocked.append(BlockedRoute(destination_name=d.name, reason="incident_type_mismatch"))
            continue
        if d.countries and case.victim.country not in d.countries:
            blocked.append(BlockedRoute(destination_name=d.name, reason="country_mismatch"))
            continue
        routes.append(Route(
            destination_name=d.name,
            priority=d.priority,
            payload_kind=d.payload_kind,
            max_tlp_allowed=d.max_tlp,
            requires_approval=d.requires_approval,
        ))
    routes.sort(key=lambda r: r.priority)
    _log.info("route.planned", case_id=case.case_id, allowed=len(routes), blocked=len(blocked))
    return routes, blocked
