"""AI-enhanced explanations via Anthropic API.

Requires Pro+ tier and anthropic_api_key in config or ANTHROPIC_API_KEY env var.
Responses are cached for 30 days in ~/.complyform/cache/explain/.
"""

from __future__ import annotations

import hashlib
import json
import os
from datetime import UTC, datetime
from pathlib import Path
from typing import TYPE_CHECKING, Any

from complyform.core.errors import (
    AIExplainAPIError,
    AIExplainKeyMissingError,
)
from complyform.core.explainer.deterministic import explain_finding
from complyform.core.explainer.models import Explanation

if TYPE_CHECKING:
    from complyform.core.assessor.control_matcher import Finding

EXPLAIN_CACHE_TTL_SECONDS = 30 * 24 * 3600  # 30 days
_CACHE_DIR = Path.home() / ".complyform" / "cache" / "explain"

_AI_MODEL = "claude-sonnet-4-5-20250929"


def resolve_api_key(config_key: str | None) -> str:
    """Resolve Anthropic API key from config or environment."""
    key = config_key or os.environ.get("ANTHROPIC_API_KEY")
    if not key:
        raise AIExplainKeyMissingError()
    return key


def ai_explain_finding(
    finding: Finding,
    *,
    api_key: str,
    cache_dir: Path | None = None,
) -> Explanation:
    """Generate an AI-enhanced explanation, with cache."""
    effective_cache_dir = cache_dir or _CACHE_DIR

    cache_key = _compute_cache_key(finding)
    cached = _read_cache(cache_key, effective_cache_dir)
    if cached is not None:
        return cached

    deterministic = explain_finding(finding)
    ai_explanation = _call_anthropic(deterministic, finding, api_key=api_key)

    _write_cache(cache_key, ai_explanation, effective_cache_dir)
    return ai_explanation


def _compute_cache_key(finding: Finding) -> str:
    """Deterministic cache key from finding identity."""
    identity = (
        f"{finding.framework}:{finding.control_id}"
        f":{finding.resource_address}:{finding.status}"
    )
    return hashlib.sha256(identity.encode()).hexdigest()[:24]


def _read_cache(cache_key: str, cache_dir: Path) -> Explanation | None:
    """Read cached explanation if present and not expired."""
    path = cache_dir / f"{cache_key}.json"
    if not path.exists():
        return None

    try:
        data: dict[str, Any] = json.loads(path.read_text(encoding="utf-8"))
        cached_at = data.get("_cached_at", "")
        cached_dt = datetime.fromisoformat(cached_at)
        age = (datetime.now(UTC) - cached_dt).total_seconds()
        if age > EXPLAIN_CACHE_TTL_SECONDS:
            path.unlink(missing_ok=True)
            return None

        data.pop("_cached_at", None)
        explanation = Explanation.model_validate(data)
        return explanation.model_copy(update={"cached": True})
    except (
        ValueError,
        TypeError,
        KeyError,
        json.JSONDecodeError,
    ):
        return None


def _write_cache(cache_key: str, explanation: Explanation, cache_dir: Path) -> None:
    """Write explanation to cache."""
    cache_dir.mkdir(parents=True, exist_ok=True)
    data = explanation.model_dump(mode="json")
    data["_cached_at"] = datetime.now(UTC).isoformat()
    path = cache_dir / f"{cache_key}.json"
    path.write_text(json.dumps(data, indent=2), encoding="utf-8")


def _call_anthropic(
    deterministic: Explanation,
    finding: Finding,
    *,
    api_key: str,
) -> Explanation:
    """Call Anthropic API for enhanced explanation."""
    import httpx

    prompt = _build_prompt(deterministic, finding)

    try:
        response = httpx.post(
            "https://api.anthropic.com/v1/messages",
            headers={
                "x-api-key": api_key,
                "anthropic-version": "2023-06-01",
                "content-type": "application/json",
            },
            json={
                "model": _AI_MODEL,
                "max_tokens": 1024,
                "messages": [{"role": "user", "content": prompt}],
            },
            timeout=30.0,
        )
        response.raise_for_status()
    except httpx.HTTPStatusError as e:
        raise AIExplainAPIError(
            e.response.status_code,
            e.response.text[:200],
        ) from e
    except httpx.RequestError as e:
        raise AIExplainAPIError(0, str(e)) from e

    body = response.json()
    ai_text = body["content"][0]["text"]

    sections = _parse_ai_response(ai_text)

    return Explanation(
        control_id=deterministic.control_id,
        framework=deterministic.framework,
        title=deterministic.title,
        severity=deterministic.severity,
        status=deterministic.status,
        summary=sections.get("summary", deterministic.summary),
        why_it_matters=sections.get("why_it_matters", deterministic.why_it_matters),
        severity_rationale=deterministic.severity_rationale,
        remediation_hint=sections.get(
            "remediation_hint",
            deterministic.remediation_hint,
        ),
        resource_address=deterministic.resource_address,
        ai_generated=True,
        model=_AI_MODEL,
        cached=False,
    )


def _build_prompt(deterministic: Explanation, finding: Finding) -> str:
    return f"""You are a cloud compliance expert. \
Explain this compliance finding in plain language.

Control: {deterministic.control_id} ({deterministic.framework})
Title: {deterministic.title}
Status: {deterministic.status}
Severity: {deterministic.severity}
Resource: {finding.resource_address} ({finding.resource_type})
Finding: {finding.finding}
Remediation: {finding.remediation}

Provide your response in exactly this format:
SUMMARY: <1-2 sentence plain-language summary>
WHY_IT_MATTERS: <2-3 sentences on business/security impact>
REMEDIATION_HINT: <concrete steps to remediate>"""


def _parse_ai_response(text: str) -> dict[str, str]:
    """Parse structured AI response into sections."""
    sections: dict[str, str] = {}
    current_key = ""
    current_lines: list[str] = []

    for line in text.strip().splitlines():
        stripped = line.strip()
        if stripped.startswith("SUMMARY:"):
            if current_key:
                sections[current_key] = " ".join(current_lines).strip()
            current_key = "summary"
            current_lines = [stripped.removeprefix("SUMMARY:").strip()]
        elif stripped.startswith("WHY_IT_MATTERS:"):
            if current_key:
                sections[current_key] = " ".join(current_lines).strip()
            current_key = "why_it_matters"
            current_lines = [stripped.removeprefix("WHY_IT_MATTERS:").strip()]
        elif stripped.startswith("REMEDIATION_HINT:"):
            if current_key:
                sections[current_key] = " ".join(current_lines).strip()
            current_key = "remediation_hint"
            current_lines = [stripped.removeprefix("REMEDIATION_HINT:").strip()]
        elif current_key:
            current_lines.append(stripped)

    if current_key:
        sections[current_key] = " ".join(current_lines).strip()

    return sections
