"""
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

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):
    session_id: str


@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
