"""Stripe payment service for subscription management."""
import stripe
from datetime import datetime
from typing import Optional, Dict
from sqlalchemy.orm import Session

from shared.config import settings
from shared.models import User, Subscription
from shared.stripe_config import PRICING_PLANS
from shared.logging_config import setup_logging

logger = setup_logging("stripe_service")

# Initialize Stripe
stripe.api_key = settings.stripe_secret_key


class StripeService:
    """Service for handling Stripe operations."""
    
    @staticmethod
    def create_customer(user: User) -> str:
        """Create a Stripe customer for a user.
        
        Args:
            user: User model instance
            
        Returns:
            Stripe customer ID
        """
        try:
            customer = stripe.Customer.create(
                email=user.email,
                name=user.username,
                metadata={
                    "user_id": user.id,
                    "username": user.username
                }
            )
            logger.info(f"Created Stripe customer {customer.id} for user {user.id}")
            return customer.id
        except stripe.error.StripeError as e:
            logger.error(f"Failed to create Stripe customer: {e}")
            raise
    
    @staticmethod
    def create_checkout_session(
        user: User,
        plan: str,
        success_url: str,
        cancel_url: str,
        db: Session
    ) -> Dict[str, str]:
        """Create a Stripe checkout session.
        
        Args:
            user: User model instance
            plan: Plan name (pro, enterprise)
            success_url: URL to redirect on success
            cancel_url: URL to redirect on cancel
            db: Database session
            
        Returns:
            Dictionary with session_id and url
        """
        try:
            # Get or create Stripe customer
            subscription = db.query(Subscription).filter(Subscription.user_id == user.id).first()
            
            if subscription and subscription.stripe_customer_id:
                customer_id = subscription.stripe_customer_id
            else:
                customer_id = StripeService.create_customer(user)
                
                # Create subscription record if it doesn't exist
                if not subscription:
                    subscription = Subscription(
                        user_id=user.id,
                        plan="free",
                        status="active",
                        stripe_customer_id=customer_id
                    )
                    db.add(subscription)
                else:
                    subscription.stripe_customer_id = customer_id
                
                db.commit()
            
            # Get price ID from config or environment
            price_id = getattr(settings, f"stripe_price_id_{plan}", None)
            
            if not price_id:
                # Create price on-the-fly for testing
                plan_config = PRICING_PLANS[plan]
                price = stripe.Price.create(
                    unit_amount=plan_config["price"],
                    currency="usd",
                    recurring={"interval": "month"},
                    product_data={
                        "name": f"{plan_config['name']} Plan",
                    },
                )
                price_id = price.id
                logger.warning(f"Created price on-the-fly: {price_id}. Set STRIPE_PRICE_ID_{plan.upper()} in env.")
            
            # Create checkout session
            session = stripe.checkout.Session.create(
                customer=customer_id,
                mode="subscription",
                line_items=[{
                    "price": price_id,
                    "quantity": 1,
                }],
                success_url=success_url,
                cancel_url=cancel_url,
                metadata={
                    "user_id": user.id,
                    "plan": plan
                }
            )
            
            logger.info(f"Created checkout session {session.id} for user {user.id}")
            
            return {
                "session_id": session.id,
                "url": session.url
            }
            
        except stripe.error.StripeError as e:
            logger.error(f"Failed to create checkout session: {e}")
            raise
    
    @staticmethod
    def cancel_subscription(
        subscription: Subscription,
        immediately: bool,
        db: Session
    ) -> Subscription:
        """Cancel a subscription.
        
        Args:
            subscription: Subscription model instance
            immediately: Cancel immediately or at period end
            db: Database session
            
        Returns:
            Updated subscription
        """
        try:
            if not subscription.stripe_subscription_id:
                raise ValueError("No active Stripe subscription")
            
            if immediately:
                stripe.Subscription.delete(subscription.stripe_subscription_id)
                subscription.status = "canceled"
                subscription.canceled_at = datetime.utcnow()
            else:
                stripe.Subscription.modify(
                    subscription.stripe_subscription_id,
                    cancel_at_period_end=True
                )
                subscription.cancel_at_period_end = True
            
            db.commit()
            db.refresh(subscription)
            
            logger.info(f"Canceled subscription {subscription.id} (immediate={immediately})")
            
            return subscription
            
        except stripe.error.StripeError as e:
            logger.error(f"Failed to cancel subscription: {e}")
            raise
    
    @staticmethod
    def handle_webhook_event(event: Dict, db: Session) -> None:
        """Handle Stripe webhook events.
        
        Args:
            event: Stripe event object
            db: Database session
        """
        event_type = event["type"]
        logger.info(f"Processing webhook event: {event_type}")
        
        if event_type == "checkout.session.completed":
            session = event["data"]["object"]
            StripeService._handle_checkout_completed(session, db)
        
        elif event_type == "customer.subscription.updated":
            subscription_data = event["data"]["object"]
            StripeService._handle_subscription_updated(subscription_data, db)
        
        elif event_type == "customer.subscription.deleted":
            subscription_data = event["data"]["object"]
            StripeService._handle_subscription_deleted(subscription_data, db)
        
        elif event_type == "invoice.payment_failed":
            invoice = event["data"]["object"]
            StripeService._handle_payment_failed(invoice, db)
    
    @staticmethod
    def _handle_checkout_completed(session: Dict, db: Session) -> None:
        """Handle successful checkout."""
        user_id = session["metadata"]["user_id"]
        plan = session["metadata"]["plan"]
        
        subscription = db.query(Subscription).filter(Subscription.user_id == user_id).first()
        
        if subscription:
            # Get Stripe subscription details
            stripe_sub_id = session["subscription"]
            stripe_sub = stripe.Subscription.retrieve(stripe_sub_id)
            
            subscription.stripe_subscription_id = stripe_sub_id
            subscription.stripe_price_id = stripe_sub["items"]["data"][0]["price"]["id"]
            subscription.plan = plan
            subscription.status = "active"
            subscription.current_period_start = datetime.fromtimestamp(stripe_sub["current_period_start"])
            subscription.current_period_end = datetime.fromtimestamp(stripe_sub["current_period_end"])
            
            # Update user tier
            user = db.query(User).filter(User.id == user_id).first()
            if user:
                user.tier = plan
            
            db.commit()
            logger.info(f"Activated subscription for user {user_id} on plan {plan}")
    
    @staticmethod
    def _handle_subscription_updated(subscription_data: Dict, db: Session) -> None:
        """Handle subscription update."""
        stripe_sub_id = subscription_data["id"]
        subscription = db.query(Subscription).filter(
            Subscription.stripe_subscription_id == stripe_sub_id
        ).first()
        
        if subscription:
            subscription.status = subscription_data["status"]
            subscription.current_period_start = datetime.fromtimestamp(
                subscription_data["current_period_start"]
            )
            subscription.current_period_end = datetime.fromtimestamp(
                subscription_data["current_period_end"]
            )
            subscription.cancel_at_period_end = subscription_data.get("cancel_at_period_end", False)
            
            db.commit()
            logger.info(f"Updated subscription {subscription.id}")
    
    @staticmethod
    def _handle_subscription_deleted(subscription_data: Dict, db: Session) -> None:
        """Handle subscription deletion."""
        stripe_sub_id = subscription_data["id"]
        subscription = db.query(Subscription).filter(
            Subscription.stripe_subscription_id == stripe_sub_id
        ).first()
        
        if subscription:
            subscription.status = "canceled"
            subscription.canceled_at = datetime.utcnow()
            subscription.plan = "free"
            
            # Update user tier
            user = db.query(User).filter(User.id == subscription.user_id).first()
            if user:
                user.tier = "free"
            
            db.commit()
            logger.info(f"Deleted subscription {subscription.id}, reverted to free")
    
    @staticmethod
    def _handle_payment_failed(invoice: Dict, db: Session) -> None:
        """Handle failed payment."""
        customer_id = invoice["customer"]
        subscription = db.query(Subscription).filter(
            Subscription.stripe_customer_id == customer_id
        ).first()
        
        if subscription:
            subscription.status = "past_due"
            db.commit()
            logger.warning(f"Payment failed for subscription {subscription.id}")
