"""
Gemini Flash client with automatic model fallback.

analyze_competitor() makes a single API call per competitor that:
  1. Extracts structured pricing plans from the raw page text
  2. Diffs against the previous snapshot
  3. Returns a plain-English summary for the finance team

Model fallback chain (free tier):
    gemini-2.0-flash-lite  →  gemini-2.0-flash  →  gemini-2.5-flash  →  gemini-flash-lite-latest
"""

import json
import os
import time

import requests

MODEL_FALLBACK = [
    "gemini-2.0-flash-lite",
    "gemini-2.0-flash",
    "gemini-2.5-flash",
    "gemini-flash-lite-latest",
]

RATE_LIMIT_SECONDS = 7.0
_last_call: float = 0.0


# ---------------------------------------------------------------------------
# Low-level Gemini call
# ---------------------------------------------------------------------------

def _call_gemini(prompt: str, model: str) -> dict | None:
    """
    Returns:
      dict   — parsed JSON response
      None   — rate-limited (caller should try next model)
      {}     — other error (caller should stop retrying)
    """
    global _last_call

    api_key = os.environ.get("GEMINI_API_KEY", "")
    if not api_key:
        raise EnvironmentError("GEMINI_API_KEY is not set")

    # Respect rate limit
    wait = RATE_LIMIT_SECONDS - (time.time() - _last_call)
    if wait > 0:
        time.sleep(wait)
    _last_call = time.time()

    url = (
        f"https://generativelanguage.googleapis.com/v1beta/models/"
        f"{model}:generateContent?key={api_key}"
    )
    payload = {
        "contents": [{"parts": [{"text": prompt}]}],
        "generationConfig": {
            "responseMimeType": "application/json",
            "temperature": 0.2,
            "maxOutputTokens": 4096,
        },
    }

    try:
        resp = requests.post(url, json=payload, timeout=60)
    except requests.RequestException as exc:
        print(f"  [Gemini/{model}] Request error: {exc}")
        return {}

    if resp.status_code == 200:
        return _parse(resp)
    if resp.status_code in (429, 503):
        print(f"  [Gemini/{model}] Rate limited — trying next model")
        time.sleep(2)
        return None  # signal fallback
    print(f"  [Gemini/{model}] HTTP {resp.status_code}: {resp.text[:200]}")
    return {}


def _parse(resp: requests.Response) -> dict:
    try:
        text = (
            resp.json()
            .get("candidates", [{}])[0]
            .get("content", {})
            .get("parts", [{}])[0]
            .get("text", "")
            .strip()
        )
        # Strip markdown code fences if present
        if text.startswith("```"):
            text = text.split("\n", 1)[-1].rsplit("```", 1)[0]
        return json.loads(text)
    except (json.JSONDecodeError, KeyError, IndexError):
        return {}


# ---------------------------------------------------------------------------
# High-level: analyze one competitor
# ---------------------------------------------------------------------------

def analyze_competitor(
    name: str,
    page_text: str,
    previous: dict,
    context: str,
) -> dict:
    """
    Single Gemini call that extracts current pricing + diffs vs previous snapshot
    + writes a finance-team summary.

    Returns a dict with keys:
      plans       — list of current plan dicts
      changes     — list of detected change dicts
      summary     — 2-3 sentence plain English summary
      has_changes — bool
    """
    previous_json = (
        json.dumps(previous, indent=2)
        if previous.get("plans")
        else "No previous data available — this is the first run for this competitor."
    )

    prompt = f"""You are a pricing intelligence analyst preparing a daily briefing for a finance team.

COMPETITOR: {name}

--- PREVIOUS SNAPSHOT ---
{previous_json}

--- CURRENT PRICING PAGE TEXT (scraped today) ---
{page_text[:8000]}

--- FINANCE TEAM CONTEXT ---
{context[:600]}

INSTRUCTIONS:
1. Extract all current pricing plans from the page text above.
   Capture: plan name, monthly price, annual price, up to 6 key features, limits (seats/storage/etc.).
   Use "Contact Sales" for enterprise plans without a listed price.

2. Compare the current plans with the previous snapshot.
   Identify: price changes, renamed plans, added/removed plans, features moving between tiers, new limits.
   If this is a first run (no previous data), set has_changes to false and leave changes empty.

3. Write a 2-3 sentence plain English summary for the finance team.
   Be specific about numbers (e.g. "raised Pro from $10 to $12/user/mo, a 20% increase").
   Flag if a competitor appears to be moving upmarket or adding a cheaper entry tier.
   If nothing changed, say so briefly.

Return ONLY valid JSON matching this exact schema — no extra keys, no markdown:
{{
  "plans": [
    {{
      "plan_name": "string",
      "monthly_price": "string (e.g. $0, $12/user/mo, Contact Sales)",
      "annual_price": "string (e.g. $0, $10/user/mo, Contact Sales)",
      "key_features": ["feature 1", "feature 2"],
      "limits": "string or empty string"
    }}
  ],
  "changes": [
    {{
      "type": "price_change | plan_added | plan_removed | feature_change | limit_change",
      "plan": "plan name",
      "field": "field that changed",
      "old": "old value",
      "new": "new value"
    }}
  ],
  "summary": "2-3 sentence summary for finance team",
  "has_changes": true
}}"""

    for model in MODEL_FALLBACK:
        result = _call_gemini(prompt, model)
        if result is None:
            # Rate limited — try next model
            continue
        if result:
            return result
        # Empty dict means a non-retriable error
        break

    return {}
