"""Billing routes — upgrade page, Stripe webhook handler."""
import os
import json

from flask import Blueprint, request, render_template, redirect, url_for, flash, jsonify

from app.models import (
    TIERS,
    STRIPE_PRICE_IDS,
    STRIPE_WEBHOOK_SECRET,
    get_user,
    update_user_tier,
    update_stripe_customer,
)
from app.crypto import hash_value
from app.routes.auth import login_required, current_user

billing_bp = Blueprint("billing", __name__, url_prefix="/billing")


@billing_bp.route("/upgrade")
@login_required
def upgrade():
    """Upgrade page — shows tier comparison and upgrade options."""
    user = current_user()

    # Build tier comparison
    tiers = []
    for key, config in TIERS.items():
        tier_info = {
            "key": key,
            "name": config["name"],
            "price": config["price"],
            "max_sites": config["max_sites"],
            "max_submissions": config["max_submissions"],
            "is_current": key == user["tier"],
            "can_upgrade": key != user["tier"] and STRIPE_PRICE_IDS.get(key),
            "stripe_price_id": STRIPE_PRICE_IDS.get(key, ""),
        }
        # Add team-specific fields
        if "max_members" in config:
            tier_info["max_members"] = config["max_members"]
        tiers.append(tier_info)

    return render_template(
        "upgrade.html",
        user=user,
        tiers=tiers,
        stripe_configured=bool(STRIPE_PRICE_IDS.get("starter")),
    )


@billing_bp.route("/stripe/webhook", methods=["POST"])
def stripe_webhook():
    """Handle Stripe webhook events.

    Expects Stripe signature header for verification.
    Idempotent — duplicate events are silently ignored via event_id dedup.
    """
    if not STRIPE_WEBHOOK_SECRET:
        return jsonify({"error": "Webhook secret not configured"}), 500

    payload = request.get_data()
    sig_header = request.headers.get("Stripe-Signature", "")

    import stripe
    stripe.api_key = os.environ.get("STRIPE_SECRET_KEY", "")

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, STRIPE_WEBHOOK_SECRET
        )
    except ValueError:
        return jsonify({"error": "Invalid payload"}), 400
    except stripe.error.SignatureVerificationError:
        return jsonify({"error": "Invalid signature"}), 400

    # ─── Idempotency: skip already-processed events ────
    if not _record_webhook_event(event.id):
        current_app.logger.info(f"stripe_webhook: duplicate event {event.id}, skipping")
        return jsonify({"received": True, "dedup": True}), 200

    # Handle events
    if event.type == "checkout.session.completed":
        session_data = event.data.object
        _handle_checkout_completed(session_data)

    elif event.type == "invoice.payment_succeeded":
        invoice_data = event.data.object
        _handle_invoice_payment_succeeded(invoice_data)

    elif event.type == "customer.subscription.updated":
        sub_data = event.data.object
        _handle_subscription_updated(sub_data)

    elif event.type == "customer.subscription.deleted":
        sub_data = event.data.object
        _handle_subscription_deleted(sub_data)

    return jsonify({"received": True}), 200


def _record_webhook_event(event_id):
    """Track processed Stripe event IDs to prevent duplicate processing.

    Returns True if event was newly recorded, False if already seen.
    """
    import time
    from app.models import get_db
    from app.db import write_lock
    conn = None
    with write_lock():
        try:
            conn = get_db()
            # Create dedup table if needed
            conn.execute("""
                CREATE TABLE IF NOT EXISTS stripe_webhook_events (
                    event_id TEXT PRIMARY KEY,
                    processed_at INTEGER NOT NULL
                )
            """)
            result = conn.execute(
                "INSERT OR IGNORE INTO stripe_webhook_events (event_id, processed_at) VALUES (?, ?)",
                (event_id, int(time.time()))
            )
            conn.commit()
            return result.rowcount > 0
        except Exception as e:
            from flask import current_app
            current_app.logger.warning(
                f"stripe_webhook: failed to record event {event_id}: {e}"
            )
            # On DB error, allow processing to avoid false negatives
            return True
        finally:
            if conn:
                conn.close()


def _handle_checkout_completed(session_data):
    """Process completed checkout session."""
    from app.models import get_db

    customer_email = session_data.get("customer_details", {}).get("email", "")
    subscription_id = session_data.get("subscription")
    price_id = session_data.get("line_items", {}).get("data", [{}])[0].get("price", {}).get("id", "")

    # Handle document invoice payments (one-time checkout)
    metadata = session_data.get("metadata", {})
    document_id = metadata.get("document_id")
    if document_id:
        from app.models import update_document_status, update_document_stripe_payment
        payment_intent = session_data.get("payment_intent", "unknown")
        update_document_status(document_id, "paid")
        update_document_stripe_payment(document_id, payment_intent, "succeeded")
        return

    # Handle subscription-based tier upgrades
    # Reverse-lookup tier from price ID
    tier = None
    for key, price_id_str in STRIPE_PRICE_IDS.items():
        if price_id_str == price_id:
            tier = key
            break

    if not tier or not customer_email:
        return

    conn = None
    try:
        conn = get_db()
        row = conn.execute("SELECT id FROM users WHERE email_hash = ?", (hash_value(customer_email.lower().strip()),)).fetchone()
    finally:
        if conn:
            conn.close()

    if row and tier:
        update_user_tier(row["id"], tier, subscription_id)


def _handle_subscription_updated(sub_data):
    """Handle subscription updates (upgrades/downgrades)."""
    from app.models import get_db

    customer_id = sub_data.get("customer")
    status = sub_data.get("status")

    if status != "active" or not customer_id:
        return

    # Find price ID from subscription items
    price_id = sub_data.get("items", {}).get("data", [{}])[0].get("price", {}).get("id", "")

    tier = None
    for key, price_id_str in STRIPE_PRICE_IDS.items():
        if price_id_str == price_id:
            tier = key
            break

    if not tier:
        return

    conn = None
    try:
        conn = get_db()
        row = conn.execute("SELECT id FROM users WHERE stripe_customer_id = ?", (customer_id,)).fetchone()
    finally:
        if conn:
            conn.close()

    if row:
        update_user_tier(row["id"], tier, sub_data.get("id"))


def _handle_subscription_deleted(sub_data):
    """Handle subscription cancellation — downgrade to free."""
    from app.models import get_db

    customer_id = sub_data.get("customer")
    if not customer_id:
        return

    conn = None
    try:
        conn = get_db()
        row = conn.execute("SELECT id FROM users WHERE stripe_customer_id = ?", (customer_id,)).fetchone()
    finally:
        if conn:
            conn.close()

    if row:
        update_user_tier(row["id"], "free")


def _handle_invoice_payment_succeeded(invoice_data):
    """Handle successful invoice payment — update document status to 'paid'."""
    from app.models import get_db, update_document_status, update_document_stripe_payment

    payment_intent = invoice_data.get("payment_intent")
    customer = invoice_data.get("customer")

    if not payment_intent:
        return

    # Find documents with this payment intent reference
    conn = None
    try:
        conn = get_db()
        rows = conn.execute(
            "SELECT document_id FROM documents WHERE stripe_payment_intent = ? OR stripe_payment_intent LIKE ?",
            (payment_intent, f"%{payment_intent}%")
        ).fetchall()
    finally:
        if conn:
            conn.close()

    if not rows:
        # Also check via customer email — find documents belonging to this customer
        if customer:
            # Look up the customer email from Stripe
            import stripe
            stripe.api_key = os.environ.get("STRIPE_SECRET_KEY", "")
            try:
                customer_obj = stripe.Customer.retrieve(customer)
                email = customer_obj.get("email", "")
                if email:
                    from app.models import list_documents_by_email
                    docs = list_documents_by_email(email)
                    for doc in docs:
                        if doc.get("status") not in ("paid", "void"):
                            update_document_status(doc["document_id"], "paid")
                            update_document_stripe_payment(
                                doc["document_id"],
                                payment_intent,
                                "succeeded",
                            )
            except Exception as e:
                from flask import current_app
                current_app.logger.warning(
                    f"invoice_payment_succeeded: Stripe customer lookup failed: {e}"
                )
        return

    # Update each matching document
    for row in rows:
        update_document_status(row["document_id"], "paid")
        update_document_stripe_payment(
            row["document_id"],
            payment_intent,
            "succeeded",
        )


@billing_bp.route("/create-checkout", methods=["POST"])
@login_required
def create_checkout():
    """Create a Stripe Checkout session for upgrading."""
    import stripe
    stripe.api_key = os.environ.get("STRIPE_SECRET_KEY", "")

    user = current_user()
    target_tier = request.form.get("tier", "").strip()

    if target_tier not in STRIPE_PRICE_IDS or not STRIPE_PRICE_IDS[target_tier]:
        flash("That tier is not available or Stripe is not configured.", "error")
        return redirect(url_for("billing.upgrade"))

    price_id = STRIPE_PRICE_IDS[target_tier]

    # Create or reuse Stripe customer
    if not user.get("stripe_customer_id"):
        customer = stripe.Customer.create(
            email=user["email"],
            name=user.get("name", "") or user["email"],
            metadata={"user_id": user["id"]},
        )
        update_stripe_customer(user["id"], customer.id)

    checkout_session = stripe.checkout.Session.create(
        customer=user["stripe_customer_id"],
        line_items=[{"price": price_id, "quantity": 1}],
        mode="subscription",
        success_url=os.environ.get("APP_URL", "https://agentforms.io") + "/auth/dashboard",
        cancel_url=os.environ.get("APP_URL", "https://agentforms.io") + "/billing/upgrade",
    )

    return redirect(checkout_session.url, code=303)
