"""Core tool implementations — pure logic, no MCP or CLI concerns.

Read operations use the env var token directly.
Write operations call vault.authorize_write() to get a PIN-decrypted token,
use it for the API call, then discard it. The token never propagates back
to the MCP or CLI layer.
"""

from clawdflare.lib import api
from clawdflare.lib.opinions import OPINIONS
from clawdflare.lib import vault


# ---------------------------------------------------------------------------
# Read operations (env var token — safe for AI to call freely)
# ---------------------------------------------------------------------------

async def zones() -> dict:
    """List all zones in the account."""
    resp = await api.get("/zones", params={"per_page": 50})
    return {
        "zones": [
            {
                "id": z["id"],
                "name": z["name"],
                "status": z["status"],
                "plan": z["plan"]["name"],
                "name_servers": z["name_servers"],
            }
            for z in resp["result"]
        ]
    }


async def zone_settings(zone: str) -> dict:
    """Get all settings for a zone."""
    zone_id = await _resolve_zone(zone)
    resp = await api.get(f"/zones/{zone_id}/settings")
    settings = {s["id"]: s["value"] for s in resp["result"]}
    return {"zone": zone, "zone_id": zone_id, "settings": settings}


async def dns_records(zone: str) -> dict:
    """List DNS records for a zone."""
    zone_id = await _resolve_zone(zone)
    resp = await api.get(f"/zones/{zone_id}/dns_records", params={"per_page": 100})
    return {
        "zone": zone,
        "records": [
            {
                "id": r["id"],
                "type": r["type"],
                "name": r["name"],
                "content": r["content"],
                "proxied": r.get("proxied", False),
                "ttl": r["ttl"],
            }
            for r in resp["result"]
        ],
    }


async def audit(zone: str) -> dict:
    """Audit a zone against opinionated best practices. Returns findings."""
    zone_id = await _resolve_zone(zone)
    resp = await api.get(f"/zones/{zone_id}/settings")
    current = {s["id"]: s["value"] for s in resp["result"]}

    findings = []
    for opinion in OPINIONS:
        setting_id = opinion["setting"]
        got = current.get(setting_id)
        want = opinion["want"]

        if got == want:
            continue

        findings.append({
            "setting": setting_id,
            "current": got,
            "recommended": want,
            "reason": opinion["reason"],
            "severity": opinion["severity"],
        })

    return {
        "zone": zone,
        "zone_id": zone_id,
        "total_opinions": len(OPINIONS),
        "passing": len(OPINIONS) - len(findings),
        "findings": sorted(findings, key=lambda f: {"critical": 0, "warning": 1, "info": 2}[f["severity"]]),
    }


async def ssl_status(zone: str) -> dict:
    """Get SSL/TLS configuration summary for a zone."""
    zone_id = await _resolve_zone(zone)
    settings_resp = await api.get(f"/zones/{zone_id}/settings")
    current = {s["id"]: s["value"] for s in settings_resp["result"]}

    return {
        "zone": zone,
        "ssl_mode": current.get("ssl"),
        "always_use_https": current.get("always_use_https"),
        "min_tls_version": current.get("min_tls_version"),
        "tls_1_3": current.get("tls_1_3"),
        "automatic_https_rewrites": current.get("automatic_https_rewrites"),
        "hsts": current.get("security_header"),
        "http3": current.get("http3"),
    }


# ---------------------------------------------------------------------------
# Write operations (PIN-protected — user must authorize via popup)
# ---------------------------------------------------------------------------

async def fix(zone: str, setting: str | None = None, dry_run: bool = False) -> dict:
    """Fix settings to match opinions. Optionally fix a single setting."""
    audit_result = await audit(zone)
    zone_id = audit_result["zone_id"]
    findings = audit_result["findings"]

    if setting:
        findings = [f for f in findings if f["setting"] == setting]
        if not findings:
            return {"zone": zone, "message": f"Setting '{setting}' already matches opinion or not found."}

    if dry_run:
        return {
            "zone": zone,
            "dry_run": True,
            "would_fix": findings,
        }

    # --- PIN authorization: token lives only in this scope ---
    token = vault.authorize_write()
    try:
        fixed = []
        errors = []
        for f in findings:
            try:
                await api.write_patch(
                    f"/zones/{zone_id}/settings/{f['setting']}",
                    {"value": f["recommended"]},
                    token,
                )
                fixed.append(f["setting"])
            except Exception as e:
                errors.append({"setting": f["setting"], "error": str(e)})
    finally:
        del token

    return {
        "zone": zone,
        "fixed": fixed,
        "errors": errors,
    }


async def set_setting(zone: str, setting: str, value) -> dict:
    """Set a specific zone setting to a value."""
    zone_id = await _resolve_zone(zone)

    # --- PIN authorization ---
    token = vault.authorize_write()
    try:
        resp = await api.write_patch(
            f"/zones/{zone_id}/settings/{setting}",
            {"value": value},
            token,
        )
    finally:
        del token

    return {
        "zone": zone,
        "setting": setting,
        "value": resp["result"]["value"],
        "success": resp.get("success", False),
    }


async def purge_cache(zone: str, everything: bool = False, urls: list[str] | None = None) -> dict:
    """Purge cache for a zone — everything or specific URLs."""
    zone_id = await _resolve_zone(zone)

    if everything:
        payload = {"purge_everything": True}
    elif urls:
        payload = {"files": urls}
    else:
        return {"error": "Specify everything=True or provide urls to purge."}

    # --- PIN authorization ---
    token = vault.authorize_write()
    try:
        resp = await api.write_post(f"/zones/{zone_id}/purge_cache", payload, token)
    finally:
        del token

    return {"zone": zone, "success": resp.get("success", False)}


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

async def _resolve_zone(zone: str) -> str:
    """Resolve a zone name to its ID. Pass-through if already an ID."""
    if len(zone) == 32 and zone.isalnum():
        return zone

    resp = await api.get("/zones", params={"name": zone})
    results = resp.get("result", [])
    if not results:
        raise ValueError(f"Zone '{zone}' not found. Check the domain name or use the zone ID.")
    return results[0]["id"]
