"""Stripe billing integration for Comply Pro/Enterprise tiers.

Handles:
- Checkout session creation for Pro ($99/mo) and Enterprise ($499/mo)
- Webhook processing for subscription lifecycle (create, cancel, renew)
- License key generation on successful payment
- License record persistence in SQLite

Requires: stripe SDK (`pip install stripe`)
Environment: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
"""
from __future__ import annotations

import json
import logging
import os
import sqlite3
import threading
from datetime import datetime, timezone
from typing import Optional

log = logging.getLogger(__name__)

# Stripe price IDs — set via environment or config
_PRICE_IDS = {
    "pro_monthly": os.environ.get("COMPLY_STRIPE_PRO_MONTHLY", ""),
    "pro_yearly": os.environ.get("COMPLY_STRIPE_PRO_YEARLY", ""),
    "enterprise_monthly": os.environ.get("COMPLY_STRIPE_ENT_MONTHLY", ""),
    "enterprise_yearly": os.environ.get("COMPLY_STRIPE_ENT_YEARLY", ""),
}

_DB_PATH = os.path.expanduser("~/.comply/licenses.db")
_db_lock = threading.Lock()


def _get_conn() -> sqlite3.Connection:
    os.makedirs(os.path.dirname(_DB_PATH), exist_ok=True)
    conn = sqlite3.connect(_DB_PATH)
    conn.row_factory = sqlite3.Row
    conn.execute("""
        CREATE TABLE IF NOT EXISTS licenses (
            id TEXT PRIMARY KEY,
            license_key TEXT NOT NULL,
            tier TEXT NOT NULL,
            customer_email TEXT,
            stripe_subscription_id TEXT,
            stripe_customer_id TEXT,
            status TEXT DEFAULT 'active',
            created_at TEXT NOT NULL,
            cancelled_at TEXT,
            metadata_json TEXT
        )
    """)
    conn.commit()
    return conn


def _get_stripe():
    """Import and configure stripe SDK."""
    try:
        import stripe
    except ImportError:
        raise RuntimeError(
            "Stripe SDK not installed. Install with: pip install stripe"
        )
    secret = os.environ.get("STRIPE_SECRET_KEY", "")
    if not secret:
        raise RuntimeError(
            "STRIPE_SECRET_KEY environment variable not set. "
            "Get your key from https://dashboard.stripe.com/apikeys"
        )
    stripe.api_key = secret
    return stripe


def create_checkout_session(
    tier: str,
    billing_period: str = "monthly",
    success_url: str = "",
    cancel_url: str = "",
    customer_email: Optional[str] = None,
) -> dict:
    """Create a Stripe Checkout session for Pro or Enterprise.

    Parameters
    ----------
    tier : str
        "pro" or "enterprise"
    billing_period : str
        "monthly" or "yearly"
    success_url : str
        URL to redirect on success (Stripe appends ?session_id={CHECKOUT_SESSION_ID})
    cancel_url : str
        URL to redirect on cancel

    Returns
    -------
    dict
        {session_id, url} — redirect the user to url
    """
    stripe = _get_stripe()

    price_key = f"{tier}_{billing_period}"
    price_id = _PRICE_IDS.get(price_key, "")
    if not price_id:
        raise ValueError(
            f"No Stripe price ID configured for {tier}/{billing_period}. "
            f"Set COMPLY_STRIPE_{tier.upper()}_{billing_period.upper()} env var."
        )

    params = {
        "mode": "subscription",
        "line_items": [{"price": price_id, "quantity": 1}],
        "success_url": success_url or "https://comply.bespokeagile.com/dashboard#/license?session_id={CHECKOUT_SESSION_ID}",
        "cancel_url": cancel_url or "https://comply.bespokeagile.com/dashboard#/scan",
        "metadata": {"tier": tier, "billing_period": billing_period},
    }
    if customer_email:
        params["customer_email"] = customer_email

    session = stripe.checkout.Session.create(**params)
    return {"session_id": session.id, "url": session.url}


def handle_webhook(payload: bytes, sig_header: str) -> dict:
    """Process a Stripe webhook event.

    Parameters
    ----------
    payload : bytes
        Raw request body
    sig_header : str
        Stripe-Signature header value

    Returns
    -------
    dict
        {event_type, handled, license_key?, message}
    """
    stripe = _get_stripe()
    webhook_secret = os.environ.get("STRIPE_WEBHOOK_SECRET", "")

    if webhook_secret:
        try:
            event = stripe.Webhook.construct_event(payload, sig_header, webhook_secret)
        except Exception as exc:
            return {"event_type": "unknown", "handled": False, "message": f"Webhook verification failed: {exc}"}
    else:
        event = json.loads(payload)

    event_type = event.get("type", "")
    data = event.get("data", {}).get("object", {})

    if event_type == "checkout.session.completed":
        return _handle_checkout_completed(data)
    elif event_type == "customer.subscription.deleted":
        return _handle_subscription_cancelled(data)
    elif event_type == "customer.subscription.updated":
        return _handle_subscription_updated(data)
    elif event_type == "invoice.payment_failed":
        return _handle_payment_failed(data)

    return {"event_type": event_type, "handled": False, "message": "Unhandled event type"}


def _handle_checkout_completed(session: dict) -> dict:
    """Generate and store a license key when checkout completes."""
    from comply.licensing import generate_license_key

    metadata = session.get("metadata", {})
    tier = metadata.get("tier", "pro")
    email = session.get("customer_email", "") or session.get("customer_details", {}).get("email", "")
    sub_id = session.get("subscription", "")
    cust_id = session.get("customer", "")

    key_data = generate_license_key(
        tier=tier,
        customer_email=email,
        stripe_subscription_id=sub_id,
    )

    # Persist license record
    with _db_lock:
        conn = _get_conn()
        conn.execute(
            "INSERT INTO licenses (id, license_key, tier, customer_email, "
            "stripe_subscription_id, stripe_customer_id, status, created_at) "
            "VALUES (?, ?, ?, ?, ?, ?, 'active', ?)",
            (sub_id or key_data["key"][:12], key_data["key"], tier, email,
             sub_id, cust_id, key_data["created_at"]),
        )
        conn.commit()

    log.info("License created: tier=%s email=%s sub=%s", tier, email, sub_id)

    return {
        "event_type": "checkout.session.completed",
        "handled": True,
        "license_key": key_data["key"],
        "tier": tier,
        "email": email,
        "message": f"License key generated for {tier} tier",
    }


def _handle_subscription_cancelled(subscription: dict) -> dict:
    """Mark license as cancelled when subscription is deleted."""
    sub_id = subscription.get("id", "")
    now = datetime.now(timezone.utc).isoformat()

    with _db_lock:
        conn = _get_conn()
        conn.execute(
            "UPDATE licenses SET status = 'cancelled', cancelled_at = ? "
            "WHERE stripe_subscription_id = ?",
            (now, sub_id),
        )
        conn.commit()

    log.info("License cancelled: sub=%s", sub_id)
    return {
        "event_type": "customer.subscription.deleted",
        "handled": True,
        "message": f"Subscription {sub_id} cancelled",
    }


def _handle_subscription_updated(subscription: dict) -> dict:
    """Handle subscription updates (plan changes, renewals)."""
    sub_id = subscription.get("id", "")
    status = subscription.get("status", "")

    if status == "active":
        with _db_lock:
            conn = _get_conn()
            conn.execute(
                "UPDATE licenses SET status = 'active' WHERE stripe_subscription_id = ?",
                (sub_id,),
            )
            conn.commit()

    return {
        "event_type": "customer.subscription.updated",
        "handled": True,
        "message": f"Subscription {sub_id} updated to {status}",
    }


def _handle_payment_failed(invoice: dict) -> dict:
    """Handle failed payment — mark license as past_due."""
    sub_id = invoice.get("subscription", "")

    with _db_lock:
        conn = _get_conn()
        conn.execute(
            "UPDATE licenses SET status = 'past_due' WHERE stripe_subscription_id = ?",
            (sub_id,),
        )
        conn.commit()

    return {
        "event_type": "invoice.payment_failed",
        "handled": True,
        "message": f"Payment failed for subscription {sub_id}",
    }


def get_license_by_subscription(sub_id: str) -> Optional[dict]:
    """Look up a license by Stripe subscription ID."""
    with _db_lock:
        conn = _get_conn()
        row = conn.execute(
            "SELECT * FROM licenses WHERE stripe_subscription_id = ?", (sub_id,)
        ).fetchone()
    if row is None:
        return None
    return dict(row)


def list_licenses(status: Optional[str] = None, limit: int = 50) -> list:
    """List all license records."""
    with _db_lock:
        conn = _get_conn()
        if status:
            rows = conn.execute(
                "SELECT * FROM licenses WHERE status = ? ORDER BY created_at DESC LIMIT ?",
                (status, limit),
            ).fetchall()
        else:
            rows = conn.execute(
                "SELECT * FROM licenses ORDER BY created_at DESC LIMIT ?", (limit,)
            ).fetchall()
    return [dict(r) for r in rows]
