"""
Stripe Integration for Payment Processing
----------------------------------------
Handles Stripe webhooks for automatic credit purchases
"""

import os
import logging
from typing import Dict, Any, Optional
from uuid import UUID

import stripe
from sqlalchemy.ext.asyncio import AsyncSession

from ..models import Account
from .tracker import SimpleUsageTracker

log = logging.getLogger(__name__)

# Initialize Stripe
stripe.api_key = os.getenv("STRIPE_SECRET_KEY", "sk_test_placeholder")
STRIPE_WEBHOOK_SECRET = os.getenv("STRIPE_WEBHOOK_SECRET", "whsec_placeholder")

# Credit packages (price_id -> credits)
CREDIT_PACKAGES = {
    "price_starter_1000": 1000,
    "price_pro_5000": 5000,
    "price_enterprise_25000": 25000,
    "price_custom": 0,  # Custom amount handled separately
}


class StripeWebhookHandler:
    """Handles Stripe webhook events for billing."""

    def __init__(self, db: AsyncSession):
        self.db = db
        self.tracker = SimpleUsageTracker(db)

    async def verify_webhook(self, payload: bytes, signature: str) -> stripe.Event:
        """Verify webhook signature and construct event."""
        try:
            event = stripe.Webhook.construct_event(
                payload, signature, STRIPE_WEBHOOK_SECRET
            )
            return event
        except ValueError as e:
            log.error(f"Invalid payload: {e}")
            raise
        except stripe.error.SignatureVerificationError as e:
            log.error(f"Invalid signature: {e}")
            raise

    async def handle_event(self, event: stripe.Event) -> Dict[str, Any]:
        """Process Stripe webhook event."""
        log.info(f"Processing Stripe event: {event.type}")

        handlers = {
            "checkout.session.completed": self._handle_checkout_completed,
            "payment_intent.succeeded": self._handle_payment_succeeded,
            "invoice.payment_succeeded": self._handle_invoice_paid,
            "customer.subscription.created": self._handle_subscription_created,
            "customer.subscription.updated": self._handle_subscription_updated,
            "customer.subscription.deleted": self._handle_subscription_cancelled,
        }

        handler = handlers.get(event.type)
        if handler:
            return await handler(event)
        else:
            log.info(f"Unhandled event type: {event.type}")
            return {"status": "ignored", "event_type": event.type}

    async def _handle_checkout_completed(self, event: stripe.Event) -> Dict[str, Any]:
        """Handle successful checkout session."""
        session = event.data.object

        # Extract metadata
        account_id = session.metadata.get("account_id")
        credits_to_add = int(session.metadata.get("credits", 0))

        if not account_id or not credits_to_add:
            log.error(f"Missing metadata in checkout session: {session.id}")
            return {"status": "error", "message": "Missing metadata"}

        # Get account
        account = await self.db.get(Account, UUID(account_id))
        if not account:
            log.error(f"Account not found: {account_id}")
            return {"status": "error", "message": "Account not found"}

        # Add credits
        account.credits_balance += credits_to_add

        # Track the purchase
        await self.tracker.track_usage(
            account_id=UUID(account_id),
            credits=-credits_to_add,  # Negative for credits added
            event_type="stripe_payment",
            metadata={
                "stripe_session_id": session.id,
                "payment_intent": session.payment_intent,
                "amount_total": session.amount_total,
                "currency": session.currency,
                "customer_email": session.customer_details.email,
                "payment_status": session.payment_status,
                "credits_purchased": credits_to_add,
            },
        )

        self.db.add(account)
        await self.db.commit()

        log.info(f"Added {credits_to_add} credits to account {account_id}")

        return {
            "status": "success",
            "account_id": account_id,
            "credits_added": credits_to_add,
            "new_balance": account.credits_balance,
        }

    async def _handle_payment_succeeded(self, event: stripe.Event) -> Dict[str, Any]:
        """Handle successful payment intent."""
        payment_intent = event.data.object

        # Check if this is a one-time credit purchase
        if payment_intent.metadata.get("type") == "credit_purchase":
            account_id = payment_intent.metadata.get("account_id")
            credits = int(payment_intent.metadata.get("credits", 0))

            if account_id and credits:
                account = await self.db.get(Account, UUID(account_id))
                if account:
                    account.credits_balance += credits

                    await self.tracker.track_usage(
                        account_id=UUID(account_id),
                        credits=-credits,
                        event_type="stripe_payment_intent",
                        metadata={
                            "payment_intent_id": payment_intent.id,
                            "amount": payment_intent.amount,
                            "currency": payment_intent.currency,
                            "credits_purchased": credits,
                        },
                    )

                    self.db.add(account)
                    await self.db.commit()

                    return {
                        "status": "success",
                        "credits_added": credits,
                        "account_id": account_id,
                    }

        return {"status": "ignored", "reason": "Not a credit purchase"}

    async def _handle_invoice_paid(self, event: stripe.Event) -> Dict[str, Any]:
        """Handle paid invoice (for subscriptions)."""
        invoice = event.data.object

        # Get subscription details
        if invoice.subscription:
            subscription = stripe.Subscription.retrieve(invoice.subscription)
            account_id = subscription.metadata.get("account_id")

            if account_id:
                # Calculate credits based on subscription plan
                credits_to_add = 0
                for item in subscription.items.data:
                    price_id = item.price.id
                    credits = CREDIT_PACKAGES.get(price_id, 0)
                    credits_to_add += credits * item.quantity

                if credits_to_add > 0:
                    account = await self.db.get(Account, UUID(account_id))
                    if account:
                        account.credits_balance += credits_to_add

                        await self.tracker.track_usage(
                            account_id=UUID(account_id),
                            credits=-credits_to_add,
                            event_type="stripe_subscription_payment",
                            metadata={
                                "invoice_id": invoice.id,
                                "subscription_id": invoice.subscription,
                                "amount_paid": invoice.amount_paid,
                                "credits_added": credits_to_add,
                                "billing_period": f"{invoice.period_start} - {invoice.period_end}",
                            },
                        )

                        self.db.add(account)
                        await self.db.commit()

                        return {
                            "status": "success",
                            "subscription_id": invoice.subscription,
                            "credits_added": credits_to_add,
                        }

        return {"status": "ignored", "reason": "No subscription metadata"}

    async def _handle_subscription_created(self, event: stripe.Event) -> Dict[str, Any]:
        """Handle new subscription creation."""
        subscription = event.data.object
        account_id = subscription.metadata.get("account_id")

        if account_id:
            # Store subscription info
            account = await self.db.get(Account, UUID(account_id))
            if account and not account.stripe_subscription_id:
                account.stripe_subscription_id = subscription.id
                self.db.add(account)
                await self.db.commit()

                log.info(
                    f"Linked subscription {subscription.id} to account {account_id}"
                )
                return {"status": "success", "subscription_id": subscription.id}

        return {"status": "ignored", "reason": "No account metadata"}

    async def _handle_subscription_updated(self, event: stripe.Event) -> Dict[str, Any]:
        """Handle subscription updates (plan changes, etc)."""
        subscription = event.data.object

        # Log the update for now
        log.info(f"Subscription updated: {subscription.id}")

        # In production, you might want to:
        # - Adjust credit allocation rates
        # - Send notification emails
        # - Update account tier/features

        return {"status": "success", "subscription_id": subscription.id}

    async def _handle_subscription_cancelled(
        self, event: stripe.Event
    ) -> Dict[str, Any]:
        """Handle subscription cancellation."""
        subscription = event.data.object
        account_id = subscription.metadata.get("account_id")

        if account_id:
            account = await self.db.get(Account, UUID(account_id))
            if account:
                # Remove subscription link
                account.stripe_subscription_id = None

                # Track the cancellation
                await self.tracker.track_usage(
                    account_id=UUID(account_id),
                    credits=0,
                    event_type="subscription_cancelled",
                    metadata={
                        "subscription_id": subscription.id,
                        "cancelled_at": subscription.canceled_at,
                        "current_period_end": subscription.current_period_end,
                    },
                )

                self.db.add(account)
                await self.db.commit()

                log.info(
                    f"Cancelled subscription {subscription.id} for account {account_id}"
                )
                return {"status": "success", "subscription_id": subscription.id}

        return {"status": "ignored", "reason": "No account metadata"}


async def create_checkout_session(
    account_id: UUID,
    credits: int,
    success_url: str,
    cancel_url: str,
    customer_email: Optional[str] = None,
) -> Dict[str, Any]:
    """Create a Stripe checkout session for credit purchase."""

    # Calculate price (e.g., $0.01 per credit)
    amount = credits * 10  # in cents

    try:
        session = stripe.checkout.Session.create(
            payment_method_types=["card"],
            line_items=[
                {
                    "price_data": {
                        "currency": "usd",
                        "product_data": {
                            "name": "FoundryMatch Credits",
                            "description": f"{credits:,} API credits",
                        },
                        "unit_amount": amount,
                    },
                    "quantity": 1,
                }
            ],
            mode="payment",
            success_url=success_url,
            cancel_url=cancel_url,
            customer_email=customer_email,
            metadata={
                "account_id": str(account_id),
                "credits": credits,
                "type": "credit_purchase",
            },
        )

        return {
            "checkout_url": session.url,
            "session_id": session.id,
            "amount": amount,
            "credits": credits,
        }

    except stripe.error.StripeError as e:
        log.error(f"Stripe error creating checkout: {e}")
        raise


async def create_subscription(
    account_id: UUID, price_id: str, customer_email: str, trial_days: int = 0
) -> Dict[str, Any]:
    """Create a subscription for recurring credit allocation."""

    try:
        # Create or get customer
        customers = stripe.Customer.list(email=customer_email, limit=1)
        if customers.data:
            customer = customers.data[0]
        else:
            customer = stripe.Customer.create(
                email=customer_email, metadata={"account_id": str(account_id)}
            )

        # Create subscription
        subscription = stripe.Subscription.create(
            customer=customer.id,
            items=[{"price": price_id}],
            trial_period_days=trial_days,
            metadata={"account_id": str(account_id)},
        )

        return {
            "subscription_id": subscription.id,
            "customer_id": customer.id,
            "status": subscription.status,
            "trial_end": subscription.trial_end,
        }

    except stripe.error.StripeError as e:
        log.error(f"Stripe error creating subscription: {e}")
        raise
