"""Model pricing data, cost calculation, and pricing scraper.

Pricing data lives in data/pricing.json (shipped with the package).
Run `cc-logger update-pricing` to scrape latest prices and update the file.
"""

from __future__ import annotations

import importlib.resources
import json
import re
import urllib.request
from datetime import datetime, timezone
from pathlib import Path

_PRICING_URL = "https://platform.claude.com/docs/en/about-claude/pricing"

# Path to the bundled pricing file inside the package
_BUNDLED_PRICING = Path(__file__).parent / "data" / "pricing.json"


def normalize_model_name(model: str) -> str:
    """Normalize model name to match pricing keys.

    Handles: claude-opus-4-5-20251101, anthropic/claude-opus-4-6, etc.
    """
    if "/" in model:
        model = model.split("/", 1)[1]
    # Strip date suffix (8+ digit segment at end)
    parts = model.split("-")
    clean = []
    for p in parts:
        if len(p) >= 8 and p.isdigit():
            break
        clean.append(p)
    return "-".join(clean)


def load_pricing() -> dict:
    """Load pricing from the bundled data/pricing.json."""
    try:
        return json.loads(_BUNDLED_PRICING.read_text())
    except (json.JSONDecodeError, OSError):
        return {"updated_at": "unknown", "source": _PRICING_URL, "models": {}}


def save_pricing(pricing: dict) -> Path:
    """Save pricing data to the bundled data/pricing.json (for repo commits)."""
    _BUNDLED_PRICING.write_text(json.dumps(pricing, indent=2) + "\n")
    return _BUNDLED_PRICING


def get_model_pricing(model: str, pricing: dict | None = None) -> dict | None:
    """Get pricing for a model. Returns {input, output, cache_read} or None."""
    if pricing is None:
        pricing = load_pricing()

    normalized = normalize_model_name(model)
    models = pricing.get("models", {})

    if normalized in models:
        return models[normalized]

    # Partial match fallback
    for key, value in models.items():
        if key.startswith(normalized) or normalized.startswith(key):
            return value

    return None


def calculate_cost(
    *,
    input_tokens: int = 0,
    output_tokens: int = 0,
    cache_tokens: int = 0,
    model: str = "",
    pricing: dict | None = None,
) -> float | None:
    """Calculate cost in USD. Returns None if model pricing unknown."""
    mp = get_model_pricing(model, pricing)
    if not mp:
        return None

    return (
        input_tokens * mp["input"] / 1_000_000
        + output_tokens * mp["output"] / 1_000_000
        + cache_tokens * mp["cache_read"] / 1_000_000
    )


def scrape_pricing() -> dict:
    """Scrape current pricing from Anthropic's pricing page."""
    req = urllib.request.Request(_PRICING_URL, headers={"User-Agent": "cc-logger/1.0"})
    with urllib.request.urlopen(req, timeout=15) as resp:
        html = resp.read().decode("utf-8")

    models = _parse_pricing_table(html)
    if not models:
        raise ValueError("Could not parse pricing table from page")

    return {
        "updated_at": datetime.now(timezone.utc).strftime("%Y-%m-%d"),
        "source": _PRICING_URL,
        "models": models,
    }


def _parse_pricing_table(html: str) -> dict:
    """Extract model pricing from HTML table rows.

    The page serves real HTML (not JS-rendered). Rows look like:
      <td>Claude Opus 4.6</td><td>$5 / MTok</td><td>$6.25 / MTok</td>
      <td>$10 / MTok</td><td>$0.50 / MTok</td><td>$25 / MTok</td>
    Columns: Model | Input | 5m Cache Write | 1h Cache Write | Cache Hits | Output
    """
    models: dict = {}
    _td = r'<td[^>]*>'
    _price = r'\$([\d.]+)\s*/\s*MTok'
    _skip_td = r'<td[^>]*>[^<]*</td>\s*'

    row_re = re.compile(
        _td + r'Claude\s+([\w\s.]+?)\s*(?:\([^)]*\)\s*)*(?:<[^>]*>\s*)*</td>\s*'  # model name (handles deprecated annotation)
        + _td + _price + r'</td>\s*'   # base input
        + _skip_td                       # 5m cache write
        + _skip_td                       # 1h cache write
        + _td + _price + r'</td>\s*'   # cache hits
        + _td + _price + r'</td>',      # output
    )

    for m in row_re.finditer(html):
        name_raw = m.group(1).strip()
        input_price = float(m.group(2))
        cache_price = float(m.group(3))
        output_price = float(m.group(4))

        # "Opus 4.6" -> "claude-opus-4-6"
        key = "claude-" + re.sub(r"[\s.]+", "-", name_raw.lower()).rstrip("-")
        models[key] = {
            "input": input_price,
            "output": output_price,
            "cache_read": cache_price,
        }

    return models
