"""Stripe billing integration for HIEROMEM SaaS."""

from __future__ import annotations

from typing import Any, Optional

from hieromem_api.settings import get_settings
from hieromem_api.tenants import get_tenant_registry

# Conditional import of stripe (optional dependency)
import importlib.util

stripe: Optional[Any] = None
if importlib.util.find_spec("stripe"):
    import importlib
    stripe = importlib.import_module("stripe")  # noqa: E402


class BillingService:

    """Handles Stripe billing operations for subscriptions."""

    def __init__(self):
        if stripe is None:
            raise RuntimeError("Stripe dependency is not installed. Install 'stripe' to enable billing.")
        settings = get_settings()
        stripe.api_key = settings.stripe_secret_key
        self.price_id_pro = settings.stripe_price_id_pro
        self.price_id_team = settings.stripe_price_id_team

    def create_customer(self, email: str, tenant_id: str, name: Optional[str] = None) -> str:
        """
        Create a Stripe customer.

        Args:
            email: Customer email
            tenant_id: HIEROMEM tenant ID
            name: Optional customer name

        Returns:
            Stripe customer ID
        """
        customer = stripe.Customer.create(
            email=email,
            name=name,
            metadata={"tenant_id": tenant_id}
        )
        return customer.id

    def create_checkout_session(
        self,
        customer_id: str,
        tier: str,
        success_url: str,
        cancel_url: str
    ) -> str:
        """
        Create a Stripe checkout session for subscription.

        Args:
            customer_id: Stripe customer ID
            tier: Target tier ('pro' or 'team')
            success_url: URL to redirect after successful payment
            cancel_url: URL to redirect if user cancels

        Returns:
            Checkout session URL
        """
        price_id = self.price_id_pro if tier == "pro" else self.price_id_team

        session = stripe.checkout.Session.create(
            customer=customer_id,
            payment_method_types=["card"],
            line_items=[{
                "price": price_id,
                "quantity": 1,
            }],
            mode="subscription",
            success_url=success_url,
            cancel_url=cancel_url,
            metadata={"tier": tier}
        )

        return session.url

    def create_portal_session(self, customer_id: str, return_url: str) -> str:
        """
        Create a Stripe customer portal session.

        Args:
            customer_id: Stripe customer ID
            return_url: URL to return to after portal session

        Returns:
            Portal session URL
        """
        session = stripe.billing_portal.Session.create(
            customer=customer_id,
            return_url=return_url,
        )
        return session.url

    def get_subscription(self, subscription_id: str) -> dict[str, Any]:
        """Get subscription details from Stripe."""
        return stripe.Subscription.retrieve(subscription_id)

    def cancel_subscription(self, subscription_id: str, at_period_end: bool = True) -> None:
        """Cancel a subscription, optionally at the end of the current period."""

        if at_period_end:
            stripe.Subscription.modify(
                subscription_id,
                cancel_at_period_end=True
            )
            return

        stripe.Subscription.delete(subscription_id)

    def upgrade_subscription(self, subscription_id: str, new_tier: str) -> None:
        """
        Upgrade/downgrade a subscription.

        Args:
            subscription_id: Stripe subscription ID
            new_tier: Target tier ('pro' or 'team')
        """
        subscription = stripe.Subscription.retrieve(subscription_id)
        new_price_id = self.price_id_pro if new_tier == "pro" else self.price_id_team

        stripe.Subscription.modify(
            subscription_id,
            items=[{
                "id": subscription["items"]["data"][0].id,
                "price": new_price_id,
            }],
            proration_behavior="create_prorations",
        )

    def handle_checkout_completed(self, session: dict[str, Any]) -> None:
        """
        Handle successful checkout completion.

        Updates tenant tier and stores Stripe IDs.
        """
        customer_id = session.get("customer")
        subscription_id = session.get("subscription")
        tier = session.get("metadata", {}).get("tier", "pro")

        # Find tenant by customer_id
        registry = get_tenant_registry()
        tenants = registry.list_all()

        for tenant in tenants:
            if tenant.stripe_customer_id == customer_id:
                # Update tenant tier and subscription
                tenant.tier = tier
                tenant.stripe_subscription_id = subscription_id
                registry.upsert(tenant)
                break

    def handle_subscription_updated(self, subscription: dict[str, Any]) -> None:
        """Handle subscription update events."""
        subscription_id = subscription.get("id")
        status = subscription.get("status")

        # Find tenant by subscription_id
        registry = get_tenant_registry()
        tenants = registry.list_all()

        for tenant in tenants:
            if tenant.stripe_subscription_id == subscription_id:
                # Update status if subscription is canceled or past_due
                if status in ["canceled", "unpaid"]:
                    tenant.tier = "free"
                    tenant.stripe_subscription_id = None
                    registry.upsert(tenant)
                break

    def handle_subscription_deleted(self, subscription: dict[str, Any]) -> None:
        """Handle subscription cancellation."""
        subscription_id = subscription.get("id")

        # Downgrade tenant to free tier
        registry = get_tenant_registry()
        tenants = registry.list_all()

        for tenant in tenants:
            if tenant.stripe_subscription_id == subscription_id:
                tenant.tier = "free"
                tenant.stripe_subscription_id = None
                registry.upsert(tenant)
                break


def get_billing_service() -> BillingService:
    """Get singleton billing service instance."""
    return BillingService()


def stripe_available() -> bool:
    """Check whether the Stripe dependency is available."""
    return stripe is not None


def get_stripe_module() -> Any:
    """Return the Stripe module if available, otherwise raise a runtime error."""
    if stripe is None:
        raise RuntimeError("Stripe dependency is not installed. Install 'stripe' to enable billing.")
    return stripe


__all__ = ["BillingService", "get_billing_service", "stripe_available", "get_stripe_module"]
