"""Cache audit — verify prompt caching claims of the provider."""
from __future__ import annotations

import asyncio
import time

from verify_core.providers.base import ChatProvider, ChatRequest
from verify_core.report import CacheAuditResult, Finding, Severity


# A deliberately long, stable "system" prompt that should be cacheable.
CACHE_SYSTEM_PROMPT = (
    "You are a highly structured technical assistant. "
    "When answering, always provide: (1) a direct answer, (2) a short "
    "justification, (3) one relevant caveat. Keep answers under 120 words. "
) * 30  # ~tall enough to exceed many providers' 1024-token cache threshold


class CacheAuditor:
    """Runs cache creation + cache read + TTL tests."""

    async def run(self, provider: ChatProvider, claimed_model: str) -> CacheAuditResult:
        findings: list[Finding] = []
        result = CacheAuditResult()

        # --- 1) creation call ---
        req1 = ChatRequest(
            model=claimed_model,
            system=CACHE_SYSTEM_PROMPT,
            messages=[{"role": "user", "content": "Say OK and nothing else."}],
            temperature=0.0,
            max_tokens=8,
            cache_control_prefix=True,
        )
        r1 = await provider.chat(req1)
        if r1.status_code != 200:
            findings.append(Finding(
                code="CACHE_ERROR",
                severity=Severity.WARN,
                title="Cache probe failed",
                detail=f"First cache request returned HTTP {r1.status_code}",
            ))
            result.findings = findings
            return result

        creation = r1.usage.cache_creation_input_tokens
        result.cache_supported = creation > 0
        if not result.cache_supported:
            findings.append(Finding(
                code="CACHE_NOT_USED",
                severity=Severity.INFO,
                title="Cache creation not observed",
                detail=(
                    "Provider did not populate cache_creation_input_tokens. "
                    "Either caching is not supported, cache_control was not honored, "
                    "or the prompt was below the provider's cache threshold."
                ),
                evidence={"usage": r1.usage.__dict__},
            ))
            result.findings = findings
            return result

        # brief pause then re-issue same prefix → should hit cache
        await asyncio.sleep(2.0)

        r2 = await provider.chat(req1)
        hit = r2.usage.cache_read_input_tokens
        result.cache_claim_matches_reality = hit > 0

        if hit == 0:
            findings.append(Finding(
                code="CACHE_NO_HIT",
                severity=Severity.WARN,
                title="Cache read not observed on identical prefix",
                detail=(
                    "Second request with identical cached prefix did not report "
                    "cache_read_input_tokens > 0. Discount may not be applied."
                ),
                evidence={"first_usage": r1.usage.__dict__, "second_usage": r2.usage.__dict__},
            ))
            # estimated overpay: 100% of what should be read-discounted
            result.estimated_overpay_pct = 90.0  # rough — 0.1x rate would save ~90%
        else:
            # verify discount is in the right ballpark (informational)
            ratio = hit / max(creation, 1)
            if ratio < 0.8:
                findings.append(Finding(
                    code="CACHE_PARTIAL_HIT",
                    severity=Severity.INFO,
                    title="Cache hit is partial",
                    detail=f"cache_read/creation = {ratio:.2f}",
                ))

        result.findings = findings
        return result
