"""
Payment Service for handling subscription payments
This service abstracts payment provider interactions and makes the system payment-agnostic
"""

import structlog
from typing import Dict, Any, Optional
import uuid
from sqlalchemy.orm import Session

from app.core.config import settings
from shared.clients.payment_client import PaymentProvider, PaymentCustomer, Subscription, PaymentMethod
from shared.clients.stripe_client import StripeProvider
from shared.database.base import create_database_manager
from app.repositories.subscription_repository import SubscriptionRepository
from app.repositories.coupon_repository import CouponRepository
from app.models.tenants import Subscription as SubscriptionModel

logger = structlog.get_logger()


class PaymentService:
    """Service for handling payment provider interactions"""

    def __init__(self, db_session: Optional[Session] = None):
        # Initialize payment provider based on configuration
        # For now, we'll use Stripe, but this can be swapped for other providers
        self.payment_provider: PaymentProvider = StripeProvider(
            api_key=settings.STRIPE_SECRET_KEY,
            webhook_secret=settings.STRIPE_WEBHOOK_SECRET
        )

        # Initialize database components
        self.database_manager = create_database_manager(settings.DATABASE_URL, "tenant-service")
        self.subscription_repo = SubscriptionRepository(SubscriptionModel, None)  # Will be set in methods
        self.db_session = db_session  # Optional session for coupon operations
    
    async def create_customer(self, user_data: Dict[str, Any]) -> PaymentCustomer:
        """Create a customer in the payment provider system"""
        try:
            customer_data = {
                'email': user_data.get('email'),
                'name': user_data.get('full_name'),
                'metadata': {
                    'user_id': user_data.get('user_id'),
                    'tenant_id': user_data.get('tenant_id')
                }
            }
            
            return await self.payment_provider.create_customer(customer_data)
        except Exception as e:
            logger.error("Failed to create customer in payment provider", error=str(e))
            raise e
    
    async def create_subscription(
        self, 
        customer_id: str, 
        plan_id: str, 
        payment_method_id: str, 
        trial_period_days: Optional[int] = None
    ) -> Subscription:
        """Create a subscription for a customer"""
        try:
            return await self.payment_provider.create_subscription(
                customer_id, 
                plan_id, 
                payment_method_id, 
                trial_period_days
            )
        except Exception as e:
            logger.error("Failed to create subscription in payment provider", error=str(e))
            raise e
    
    def validate_coupon_code(
        self,
        coupon_code: str,
        tenant_id: str,
        db_session: Session
    ) -> Dict[str, Any]:
        """
        Validate a coupon code for a tenant.
        Returns validation result with discount preview.
        """
        try:
            coupon_repo = CouponRepository(db_session)
            validation = coupon_repo.validate_coupon(coupon_code, tenant_id)

            return {
                "valid": validation.valid,
                "error_message": validation.error_message,
                "discount_preview": validation.discount_preview,
                "coupon": {
                    "code": validation.coupon.code,
                    "discount_type": validation.coupon.discount_type.value,
                    "discount_value": validation.coupon.discount_value
                } if validation.coupon else None
            }

        except Exception as e:
            logger.error("Failed to validate coupon", error=str(e), coupon_code=coupon_code)
            return {
                "valid": False,
                "error_message": "Error al validar el cupón",
                "discount_preview": None,
                "coupon": None
            }

    def redeem_coupon(
        self,
        coupon_code: str,
        tenant_id: str,
        db_session: Session,
        base_trial_days: int = 14
    ) -> tuple[bool, Optional[Dict[str, Any]], Optional[str]]:
        """
        Redeem a coupon for a tenant.
        Returns (success, discount_applied, error_message)
        """
        try:
            coupon_repo = CouponRepository(db_session)
            success, redemption, error = coupon_repo.redeem_coupon(
                coupon_code,
                tenant_id,
                base_trial_days
            )

            if success and redemption:
                return True, redemption.discount_applied, None
            else:
                return False, None, error

        except Exception as e:
            logger.error("Failed to redeem coupon", error=str(e), coupon_code=coupon_code)
            return False, None, f"Error al aplicar el cupón: {str(e)}"

    async def process_registration_with_subscription(
        self,
        user_data: Dict[str, Any],
        plan_id: str,
        payment_method_id: str,
        use_trial: bool = False,
        coupon_code: Optional[str] = None,
        db_session: Optional[Session] = None
    ) -> Dict[str, Any]:
        """Process user registration with subscription creation"""
        try:
            # Create customer in payment provider
            customer = await self.create_customer(user_data)

            # Determine trial period (default 14 days)
            trial_period_days = 14 if use_trial else 0

            # Apply coupon if provided
            coupon_discount = None
            if coupon_code and db_session:
                # Redeem coupon
                success, discount, error = self.redeem_coupon(
                    coupon_code,
                    user_data.get('tenant_id'),
                    db_session,
                    trial_period_days
                )

                if success and discount:
                    coupon_discount = discount
                    # Update trial period if coupon extends it
                    if discount.get("type") == "trial_extension":
                        trial_period_days = discount.get("total_trial_days", trial_period_days)
                        logger.info(
                            "Coupon applied successfully",
                            coupon_code=coupon_code,
                            extended_trial_days=trial_period_days
                        )
                else:
                    logger.warning("Failed to apply coupon", error=error, coupon_code=coupon_code)

            # Create subscription
            subscription = await self.create_subscription(
                customer.id,
                plan_id,
                payment_method_id,
                trial_period_days if trial_period_days > 0 else None
            )

            # Save subscription to database
            async with self.database_manager.get_session() as session:
                self.subscription_repo.session = session
                subscription_data = {
                    'id': str(uuid.uuid4()),
                    'tenant_id': user_data.get('tenant_id'),
                    'customer_id': customer.id,
                    'subscription_id': subscription.id,
                    'plan_id': plan_id,
                    'status': subscription.status,
                    'current_period_start': subscription.current_period_start,
                    'current_period_end': subscription.current_period_end,
                    'created_at': subscription.created_at,
                    'trial_period_days': trial_period_days if trial_period_days > 0 else None
                }
                subscription_record = await self.subscription_repo.create(subscription_data)

            result = {
                'customer_id': customer.id,
                'subscription_id': subscription.id,
                'status': subscription.status,
                'trial_period_days': trial_period_days
            }

            # Include coupon info if applied
            if coupon_discount:
                result['coupon_applied'] = {
                    'code': coupon_code,
                    'discount': coupon_discount
                }

            return result

        except Exception as e:
            logger.error("Failed to process registration with subscription", error=str(e))
            raise e
    
    async def cancel_subscription(self, subscription_id: str) -> Subscription:
        """Cancel a subscription in the payment provider"""
        try:
            return await self.payment_provider.cancel_subscription(subscription_id)
        except Exception as e:
            logger.error("Failed to cancel subscription in payment provider", error=str(e))
            raise e
    
    async def update_payment_method(self, customer_id: str, payment_method_id: str) -> PaymentMethod:
        """Update the payment method for a customer"""
        try:
            return await self.payment_provider.update_payment_method(customer_id, payment_method_id)
        except Exception as e:
            logger.error("Failed to update payment method in payment provider", error=str(e))
            raise e
    
    async def get_invoices(self, customer_id: str) -> list:
        """Get invoices for a customer from the payment provider"""
        try:
            return await self.payment_provider.get_invoices(customer_id)
        except Exception as e:
            logger.error("Failed to get invoices from payment provider", error=str(e))
            raise e
    
    async def get_subscription(self, subscription_id: str) -> Subscription:
        """Get subscription details from the payment provider"""
        try:
            return await self.payment_provider.get_subscription(subscription_id)
        except Exception as e:
            logger.error("Failed to get subscription from payment provider", error=str(e))
            raise e
