"""
PULSE API — License router. Endpoints for license key generation and Stripe webhooks.
"""
from __future__ import annotations

import hashlib
import hmac
import os
import time
from collections import defaultdict

from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel, Field

from pulse.core.license import LicenseManager, PRICE_TO_PLAN

router = APIRouter(prefix="/v1/license", tags=["license"])

# Simple in-memory rate limiter: IP → list of timestamps
_rate_limits: dict[str, list[float]] = defaultdict(list)
RATE_LIMIT = 10  # max requests per window
RATE_WINDOW = 60  # seconds


def _check_rate_limit(ip: str):
    now = time.time()
    _rate_limits[ip] = [t for t in _rate_limits[ip] if now - t < RATE_WINDOW]
    if len(_rate_limits[ip]) >= RATE_LIMIT:
        raise HTTPException(status_code=429, detail="Rate limit exceeded. Try again later.")
    _rate_limits[ip].append(now)


class GenerateRequest(BaseModel):
    # S33: validate session_id to prevent path traversal in Stripe URL f-string
    session_id: str = Field(..., pattern=r'^cs_[a-zA-Z0-9_]+$')


@router.post("/generate")
async def generate_license(req: GenerateRequest, request: Request):
    """Generate a license key from a Stripe checkout session ID."""
    _check_rate_limit(request.client.host if request.client else "unknown")

    stripe_secret = os.environ.get("STRIPE_SECRET_KEY")
    if not stripe_secret:
        raise HTTPException(status_code=500, detail="Stripe not configured.")

    # Fetch checkout session from Stripe
    try:
        import requests
        resp = requests.get(
            f"https://api.stripe.com/v1/checkout/sessions/{req.session_id}",
            auth=(stripe_secret, ""),
            timeout=10,
        )
        if resp.status_code != 200:
            raise HTTPException(status_code=400, detail="Invalid session ID.")
        session = resp.json()
    except HTTPException:
        raise
    except Exception:
        raise HTTPException(status_code=502, detail="Failed to reach Stripe.")

    customer_id = session.get("customer")
    if not customer_id:
        raise HTTPException(status_code=400, detail="No customer found in session.")

    # Determine plan from subscription's price
    sub_id = session.get("subscription")
    plan = "solo"  # default
    if sub_id:
        try:
            sub_resp = requests.get(
                f"https://api.stripe.com/v1/subscriptions/{sub_id}",
                auth=(stripe_secret, ""),
                timeout=10,
            )
            if sub_resp.status_code == 200:
                sub_data = sub_resp.json()
                items = sub_data.get("items", {}).get("data", [])
                if items:
                    price_id = items[0].get("price", {}).get("id", "")
                    plan = PRICE_TO_PLAN.get(price_id, "solo")
        except Exception:
            pass

    # Generate signed key
    lm = LicenseManager()
    key = lm.generate_key(plan, customer_id)

    return {
        "key": key,
        "plan": plan,
        "instructions": [
            "pip install pulse-os",
            f"pulse activate {key}",
            "pulse status",
        ],
    }


@router.post("/webhooks/stripe")
async def stripe_webhook(request: Request):
    """Handle Stripe webhook events (subscription changes)."""
    webhook_secret = os.environ.get("STRIPE_WEBHOOK_SECRET")
    if not webhook_secret:
        raise HTTPException(status_code=500, detail="Webhook secret not configured.")

    body = await request.body()
    sig_header = request.headers.get("stripe-signature", "")

    # Verify webhook signature
    if not _verify_stripe_signature(body, sig_header, webhook_secret):
        raise HTTPException(status_code=400, detail="Invalid signature.")

    try:
        import json
        event = json.loads(body)
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid JSON.")

    event_type = event.get("type", "")

    # Log relevant events (future: instant revocation / plan change)
    if event_type in ("customer.subscription.deleted", "customer.subscription.updated"):
        customer = event.get("data", {}).get("object", {}).get("customer", "unknown")
        status = event.get("data", {}).get("object", {}).get("status", "unknown")
        print(f"[PULSE] Stripe webhook: {event_type} customer={customer} status={status}")

    return {"received": True}


def _verify_stripe_signature(payload: bytes, sig_header: str, secret: str) -> bool:
    """Verify Stripe webhook signature (v1 scheme)."""
    try:
        parts = dict(item.split("=", 1) for item in sig_header.split(",") if "=" in item)
        timestamp = parts.get("t", "")
        signature = parts.get("v1", "")
        if not timestamp or not signature:
            return False
        signed_payload = f"{timestamp}.".encode() + payload
        expected = hmac.new(
            secret.encode(), signed_payload, hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(expected, signature)
    except Exception:
        return False
