from django.shortcuts import get_object_or_404
from django.conf import settings
from django.urls import reverse
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
import stripe
from datetime import datetime, timedelta

from ..models import TeamRegistration, PlayerRegistration, Tournament
from ..models.player_registration import PlayerPaymentType
from .email_service import TournamentEmailService
from tournaments.services.currency_service import CurrencyService

class PaymentService:
    """
    Service for handling payment processing for tournament registrations
    """

    def __init__(self, request):
        self.request = request
        self.stripe_api_key = settings.STRIPE_SECRET_KEY

    def create_checkout_session(self, tournament_id, team_fee, cart_manager=None, team_registration_id=None):
        """
        Create a Stripe checkout session for tournament payment
        """
        print(f"[TOURNAMENT PAYMENT] Creating checkout session")
        print(f"[TOURNAMENT PAYMENT] Tournament ID: {tournament_id}")
        print(f"[TOURNAMENT PAYMENT] Team fee: {team_fee}")
        print(f"[TOURNAMENT PAYMENT] Cart manager: {cart_manager}")
        print(f"[TOURNAMENT PAYMENT] Team registration ID: {team_registration_id}")
        print(f"[TOURNAMENT PAYMENT] User: {self.request.user}")
        session_duration_minutes = 30
        expires_at = int((datetime.now() + timedelta(minutes=session_duration_minutes)).timestamp())

        stripe.api_key = self.stripe_api_key
        tournament = get_object_or_404(Tournament, id=tournament_id)
        user = self.request.user if self.request.user.is_authenticated else None
        customer_email = user.email if user else None
        customer_name = f"{user.first_name} {user.last_name}".strip() if user and user.first_name else None
        registration_type = 'direct'
        if not team_registration_id:
            registration_type = 'cart'

        print(f"[TOURNAMENT PAYMENT] Tournament: {tournament.name}")
        print(f"[TOURNAMENT PAYMENT] Customer email: {customer_email}")
        print(f"[TOURNAMENT PAYMENT] Customer name: {customer_name}")
        print(f"[TOURNAMENT PAYMENT] Registration type: {registration_type}")

        currency_service = CurrencyService()

        # Check if payments are enabled for this tournament
        if not tournament.should_request_payment():
            print(f"[TOURNAMENT PAYMENT] Payments not enabled for tournament")
            raise Exception("Les paiements ne sont pas activés pour ce tournoi.")

        # Get currency code and validate it
        currency_code = tournament.currency_code or 'EUR'
        if not currency_service.validate_currency_code(currency_code):
            print(f"[TOURNAMENT PAYMENT] Invalid currency code: {currency_code}")
            raise Exception(f"Devise non supportée: {currency_code}")

        print(f"[TOURNAMENT PAYMENT] Currency code: {currency_code}")

        # Convert amount to Stripe format
        stripe_amount = currency_service.convert_to_stripe_amount(team_fee, currency_code)
        print(f"[TOURNAMENT PAYMENT] Stripe amount: {stripe_amount}")

        # Get user email if authenticated
        customer_email = self.request.user.email if self.request.user.is_authenticated else None

        # Determine the appropriate cancel URL based on the context
        if not team_registration_id and cart_manager:
            team_registration = self._process_pre_registration_payment(cart_manager)
            if not team_registration:
                print(f"[TOURNAMENT PAYMENT] Failed to create team registration")
                raise Exception("Erreur lors de la création de la réservation")
            team_registration_id = team_registration.id
            print(f"[TOURNAMENT PAYMENT] Created team registration: {team_registration_id}")

        if not team_registration_id:
            print(f"[TOURNAMENT PAYMENT] No team registration ID available")
            raise Exception("Erreur lors de la création de la réservation")

        # Determine the appropriate cancel URL based on the context
        if registration_type == 'direct':
            # If we're paying for an existing registration, go back to tournament info
            cancel_url = self.request.build_absolute_uri(
                reverse('tournament-info', kwargs={'tournament_id': tournament_id})
            )
        else:
            # If we're in the registration process, go back to registration form
            self.request.session['cancel_team_registration_id'] = str(team_registration_id)
            cancel_url = self.request.build_absolute_uri(
                reverse('register_tournament', kwargs={
                    'tournament_id': tournament_id,
                })
            )

        print(f"[TOURNAMENT PAYMENT] Cancel URL: {cancel_url}")

        base_metadata = {
            'tournament_id': str(tournament_id),
            'team_registration_id': str(team_registration_id),
            'customer_name': customer_name or 'Non fourni',
            'customer_email': customer_email or 'Non fourni',
            'user_id': str(self.request.user.id) if self.request.user.is_authenticated else None,
            'payment_source': 'tournament',  # Identify payment source
            'registration_type': registration_type,
            'source_page': 'tournament_info' if team_registration_id else 'register_tournament',
            'currency_code': currency_code,  # Store currency for later reference
        }

        print(f"[TOURNAMENT PAYMENT] Base metadata: {base_metadata}")

        if tournament.is_corporate_tournament:
            print(f"[TOURNAMENT PAYMENT] Corporate tournament - using direct payment")
            # Corporate tournament metadata
            metadata = {
                **base_metadata,
                'is_corporate_tournament': 'true',
                'stripe_account_type': 'direct'
            }
        else:
            print(f"[TOURNAMENT PAYMENT] Regular tournament - using Stripe Connect")
            # Regular tournament metadata
            metadata = {
                **base_metadata,
                'is_corporate_tournament': 'false',
                'stripe_account_type': 'connect',
                'stripe_account_id': tournament.stripe_account_id
            }

        self.request.session['team_registration_id'] = str(team_registration_id)

        metadata.update({
            'tournament_name': tournament.broadcast_display_name(),
            'tournament_date': tournament.formatted_start_date(),
            'tournament_club': tournament.event.club.name,
            'tournament_fee': str(team_fee)
        })

        print(f"[TOURNAMENT PAYMENT] Final metadata: {metadata}")

        # Common checkout session parameters
        if tournament.is_corporate_tournament:
            # Direct charge without transfers when umpire is platform owner
            checkout_session_params = {
                'payment_method_types': ['card'],
                'expires_at': expires_at,
                'line_items': [{
                    'price_data': {
                        'currency': currency_code.lower(),  # Use tournament currency
                        'product_data': {
                            'name': f'{tournament.broadcast_display_name()} du {tournament.formatted_start_date()}',
                            'description': f'Lieu {tournament.event.club.name}',
                        },
                        'unit_amount': stripe_amount,  # Amount in proper currency format
                    },
                    'quantity': 1,
                }],
                'mode': 'payment',
                'success_url': self.request.build_absolute_uri(
                    reverse('tournament-payment-success', kwargs={'tournament_id': tournament_id})
                ),
                'cancel_url': cancel_url,
                'metadata': metadata
            }
            print(f"[TOURNAMENT PAYMENT] Corporate checkout params: {checkout_session_params}")
        else:
            # Get the umpire's Stripe account ID
            stripe_account_id = tournament.stripe_account_id
            if not stripe_account_id:
                print(f"[TOURNAMENT PAYMENT] No Stripe account ID for umpire")
                raise Exception("L'arbitre n'a pas configuré son compte Stripe.")

            print(f"[TOURNAMENT PAYMENT] Umpire Stripe account: {stripe_account_id}")

            # Calculate commission
            commission_rate = tournament.event.creator.effective_commission_rate()
            platform_amount = currency_service.convert_to_stripe_amount(
                team_fee * commission_rate, currency_code
            )

            print(f"[TOURNAMENT PAYMENT] Commission rate: {commission_rate}")
            print(f"[TOURNAMENT PAYMENT] Platform amount: {platform_amount}")

            # Direct charge on connected account - this will appear in umpire's dashboard
            checkout_session_params = {
                'payment_method_types': ['card'],
                'expires_at': expires_at,
                'line_items': [{
                    'price_data': {
                        'currency': currency_code.lower(),
                        'product_data': {
                            'name': f'{tournament.broadcast_display_name()} du {tournament.formatted_start_date()}',
                            'description': f'Lieu {tournament.event.club.name}',
                        },
                        'unit_amount': stripe_amount,
                    },
                    'quantity': 1,
                }],
                'mode': 'payment',
                'success_url': self.request.build_absolute_uri(
                    reverse('tournament-payment-success', kwargs={'tournament_id': tournament_id})
                ),
                'cancel_url': cancel_url,
                'payment_intent_data': {
                    'application_fee_amount': platform_amount,  # Your commission
                    'description': f'Inscription {tournament.broadcast_display_name()} du {tournament.formatted_start_date()}',
                    'metadata': metadata  # All metadata will be visible to umpire
                },
                'metadata': metadata  # Session metadata
            }
            print(f"[TOURNAMENT PAYMENT] Direct charge checkout params: {checkout_session_params}")

        # Add customer_email if available
        if customer_email:
            checkout_session_params['customer_email'] = customer_email
            print(f"[TOURNAMENT PAYMENT] Added customer email to params")

        # Create the checkout session
        try:
            print(f"[TOURNAMENT PAYMENT] Creating Stripe checkout session...")
            if tournament.is_corporate_tournament:
                # Create on platform account
                checkout_session = stripe.checkout.Session.create(**checkout_session_params)
            else:
                # Create on connected account (direct charge)
                stripe_account_id = tournament.stripe_account_id
                self.request.session['stripe_account_id'] = stripe_account_id if not tournament.is_corporate_tournament else None
                checkout_session = stripe.checkout.Session.create(
                    **checkout_session_params,
                    stripe_account=stripe_account_id  # This creates the session on the connected account
                )

            # Store checkout session ID and source page in session
            self.request.session['stripe_checkout_session_id'] = checkout_session.id
            self.request.session['payment_source_page'] = 'tournament_info' if team_registration_id else 'register_tournament'
            self.request.session.modified = True

            print(f"[TOURNAMENT PAYMENT] Checkout session created successfully: {checkout_session.id}")
            print(f"[TOURNAMENT PAYMENT] Stored session data - checkout_session_id: {checkout_session.id}")

            return checkout_session
        except stripe.error.StripeError as e:
            print(f"[TOURNAMENT PAYMENT] Stripe error: {str(e)}")
            # Handle specific Stripe errors more gracefully
            if 'destination' in str(e):
                raise Exception("Erreur avec le compte Stripe de l'arbitre. Contactez l'administrateur.")
            else:
                raise Exception(f"Erreur Stripe: {str(e)}")

    def process_successful_payment(self, checkout_session):
        """
        Process a successful Stripe payment
        Returns a tuple (success, redirect_response)
        """

        success = PaymentService.process_direct_payment(checkout_session)

        # Print combined payment status
        print(f"process_direct_payment: {success}")

        # Clear checkout session ID
        if 'stripe_checkout_session_id' in self.request.session:
            del self.request.session['stripe_checkout_session_id']

        return success

    def _process_pre_registration_payment(self, cart_manager):
        """Process payment made during registration"""
        # Checkout and create registration
        success, result = cart_manager.checkout(confirmed=False)
        if not success:
            return None

        # Process payment for the new registration
        team_registration = result  # result is team_registration object
        team_registration.confirm_pre_registration()
        # self._update_registration_payment_info(
        #     team_registration,
        #     checkout_session.payment_intent
        # )

        # # Send confirmation email if appropriate
        # waiting_list_position = cart_data.get('waiting_list_position', -1)
        # if is_not_sqlite_backend():
        #     email_service = TournamentEmailService()
        #     email_service.send_registration_confirmation(
        #         self.request,
        #         tournament,
        #         team_registration,
        #         waiting_list_position
        #     )

        return team_registration

    # def _update_registration_payment_info(self, team_registration, payment_intent_id):
    #     """Update player registrations with payment information"""
    #     team_registration.confirm_registration(payment_intent_id)
    #     return True

    def process_refund(self, team_registration_id, force_refund=False):
        """
        Process a refund for a tournament registration as part of unregistration
        Returns a tuple (success, message)
        """
        stripe.api_key = self.stripe_api_key

        try:
            # Get the team registration
            team_registration = get_object_or_404(TeamRegistration, id=team_registration_id)
            tournament = team_registration.tournament

            # Check if refund is possible for this tournament
            if not tournament.is_refund_possible() and force_refund == False:
                return False, "Les remboursements ne sont plus possibles pour ce tournoi.", None

            # Get payment ID from player registrations
            player_registrations = PlayerRegistration.objects.filter(team_registration=team_registration)
            payment_id = None

            for player_reg in player_registrations:
                # Find the first valid payment ID
                if player_reg.payment_id and player_reg.payment_type == PlayerPaymentType.CREDIT_CARD:
                    payment_id = player_reg.payment_id
                    break

            if not payment_id:
                return False, "Aucun paiement trouvé pour cette équipe.", None

            # Get the Stripe payment intent from the correct account
            try:
                if tournament.is_corporate_tournament:
                    # Corporate tournament - payment on platform account
                    payment_intent = stripe.PaymentIntent.retrieve(payment_id)
                else:
                    # Regular tournament - payment on connected account
                    if not tournament.stripe_account_id:
                        return False, "Compte Stripe de l'arbitre non configuré.", None

                    #legacy retrieval
                    try:
                        payment_intent = stripe.PaymentIntent.retrieve(payment_id)
                    except:
                        payment_intent = stripe.PaymentIntent.retrieve(
                            payment_id,
                            stripe_account=tournament.stripe_account_id
                        )
            except stripe.error.InvalidRequestError as e:
                return False, f"Paiement introuvable: {str(e)}", None

            if payment_intent.status != 'succeeded':
                return False, "Le paiement n'a pas été complété, il ne peut pas être remboursé.", None

            # Process the refund - with different parameters based on tournament type
            if tournament.is_corporate_tournament:
                # Corporate tournament refund (simple refund)
                refund = stripe.Refund.create(
                    payment_intent=payment_id
                )
            else:
                # Direct charge refund (on connected account)
                # Check if there's an application fee to refund
                refund_params = {
                    'payment_intent': payment_id,
                    'stripe_account': tournament.stripe_account_id
                }

                # Only add refund_application_fee if there's actually an application fee
                if hasattr(payment_intent, 'application_fee_amount') and payment_intent.application_fee_amount and payment_intent.application_fee_amount > 0:
                    refund_params['refund_application_fee'] = True
                    print(f"[REFUND] Refunding application fee of {payment_intent.application_fee_amount}")
                else:
                    print(f"[REFUND] No application fee to refund")

                refund = stripe.Refund.create(**refund_params)

            for player_reg in player_registrations:
                player_reg.payment_type = None
                player_reg.payment_id = None
                player_reg.save()

            TournamentEmailService.send_refund_confirmation(tournament, team_registration, refund)

            # Return success with refund object
            return True, "L'inscription a été remboursée automatiquement.", refund

        except stripe.error.StripeError as e:
            return False, f"Erreur de remboursement Stripe: {str(e)}", None
        except Exception as e:
            return False, f"Erreur lors du remboursement: {str(e)}", None


    @staticmethod
    def process_failed_payment_intent(payment_intent):
        """Process a failed Payment Intent"""
        if hasattr(payment_intent, 'metadata'):
            metadata = payment_intent.metadata
        elif isinstance(payment_intent, dict) and 'metadata' in payment_intent:
            metadata = payment_intent['metadata']
        else:
            print("[FAILED PAYMENT] No metadata found in payment intent")
            return False

        print(f"[FAILED PAYMENT] Processing failed payment intent")
        print(f"[FAILED PAYMENT] Metadata: {metadata}")

        tournament_id = metadata.get('tournament_id')
        team_registration_id = metadata.get('team_registration_id')
        registration_type = metadata.get('registration_type')

        print(f"[FAILED PAYMENT] Tournament ID: {tournament_id}")
        print(f"[FAILED PAYMENT] Team Registration ID: {team_registration_id}")
        print(f"[FAILED PAYMENT] Registration Type: {registration_type}")

        # Release reserved spot for cart registrations
        if registration_type == 'cart' and tournament_id:
            try:
                tournament = Tournament.objects.get(id=tournament_id)
                old_spots = tournament.reserved_spots
                tournament.reserved_spots = max(0, tournament.reserved_spots - 1)
                tournament.save()
                print(f"[FAILED PAYMENT] Released reserved spot: {old_spots} → {tournament.reserved_spots}")
            except Tournament.DoesNotExist:
                print(f"[FAILED PAYMENT] Tournament {tournament_id} not found")
            except Exception as e:
                print(f"[FAILED PAYMENT] Error updating tournament reserved spots: {str(e)}")

        # Clean up unpaid team registration
        if not team_registration_id:
            print("[FAILED PAYMENT] No team registration ID found in metadata")
            return False

        try:
            print(f"[FAILED PAYMENT] Looking for team registration with ID: {team_registration_id}")
            team_registration = TeamRegistration.objects.get(id=team_registration_id)

            if not team_registration.is_paid():
                team_registration.delete()
                print(f"[FAILED PAYMENT] Deleted unpaid team registration {team_registration_id}")
            else:
                print(f"[FAILED PAYMENT] Team registration {team_registration_id} is already paid")

            return True

        except TeamRegistration.DoesNotExist:
            print(f"[FAILED PAYMENT] Team registration {team_registration_id} not found")
            return False
        except Exception as e:
            print(f"[FAILED PAYMENT] Error processing team registration: {str(e)}")
            return False

    @staticmethod
    def process_expired_checkout_session(checkout_session):
        """Process an expired Checkout Session"""
        if hasattr(checkout_session, 'metadata'):
            metadata = checkout_session.metadata
        elif isinstance(checkout_session, dict) and 'metadata' in checkout_session:
            metadata = checkout_session['metadata']
        else:
            print("[EXPIRED SESSION] No metadata found in checkout session")
            return False

        print(f"[EXPIRED SESSION] Processing expired checkout session")
        print(f"[EXPIRED SESSION] Metadata: {metadata}")

        tournament_id = metadata.get('tournament_id')
        team_registration_id = metadata.get('team_registration_id')
        registration_type = metadata.get('registration_type')

        print(f"[EXPIRED SESSION] Tournament ID: {tournament_id}")
        print(f"[EXPIRED SESSION] Team Registration ID: {team_registration_id}")
        print(f"[EXPIRED SESSION] Registration Type: {registration_type}")

        # Release reserved spot for cart registrations
        if registration_type == 'cart' and tournament_id:
            try:
                tournament = Tournament.objects.get(id=tournament_id)
                old_spots = tournament.reserved_spots
                tournament.reserved_spots = max(0, tournament.reserved_spots - 1)
                tournament.save()
                print(f"[EXPIRED SESSION] Released reserved spot: {old_spots} → {tournament.reserved_spots}")
            except Tournament.DoesNotExist:
                print(f"[EXPIRED SESSION] Tournament {tournament_id} not found")
            except Exception as e:
                print(f"[EXPIRED SESSION] Error updating tournament reserved spots: {str(e)}")

        # Clean up unpaid team registration
        if not team_registration_id:
            print("[EXPIRED SESSION] No team registration ID found in metadata")
            return False

        try:
            print(f"[EXPIRED SESSION] Looking for team registration with ID: {team_registration_id}")
            team_registration = TeamRegistration.objects.get(id=team_registration_id)

            if not team_registration.is_paid():
                team_registration.delete()
                print(f"[EXPIRED SESSION] Deleted unpaid team registration {team_registration_id}")
            else:
                print(f"[EXPIRED SESSION] Team registration {team_registration_id} is already paid")

            return True

        except TeamRegistration.DoesNotExist:
            print(f"[EXPIRED SESSION] Team registration {team_registration_id} not found")
            return True
        except Exception as e:
            print(f"[EXPIRED SESSION] Error processing team registration: {str(e)}")
            return False

    @staticmethod
    def process_failed_or_expired_session(stripe_object):
        """Legacy method for backward compatibility - delegates to specific handlers"""
        # Try to determine object type and delegate
        if hasattr(stripe_object, 'object'):
            object_type = stripe_object.object
        elif isinstance(stripe_object, dict) and 'object' in stripe_object:
            object_type = stripe_object['object']
        else:
            print("[LEGACY HANDLER] Cannot determine stripe object type")
            return False

        print(f"[LEGACY HANDLER] Delegating {object_type} to specific handler")

        if object_type == 'payment_intent':
            return PaymentService.process_failed_payment_intent(stripe_object)
        elif object_type == 'checkout.session':
            return PaymentService.process_expired_checkout_session(stripe_object)
        else:
            print(f"[LEGACY HANDLER] Unknown object type: {object_type}")
            return False

    @staticmethod
    def process_direct_payment(checkout_session):
        """Process payment for an existing team registration"""
        metadata = checkout_session.metadata
        tournament_id = metadata.get('tournament_id')
        team_registration_id = metadata.get('team_registration_id')
        registration_type = metadata.get('registration_type')

        if tournament_id and registration_type == 'cart':
            try:
                tournament = Tournament.objects.get(id=tournament_id)
                tournament.reserved_spots = max(0, tournament.reserved_spots - 1)
                tournament.save()
                print(f"Decreased reserved spots for tournament {tournament_id} after payment failure")
            except Tournament.DoesNotExist:
                print(f"Tournament not found with ID: {tournament_id}")
            except Exception as e:
                print(f"Error saving tournament for team registration: {str(e)}")

        if not team_registration_id:
            print("No team registration ID found in session")
            return False

        try:
            print(f"Looking for team registration with ID: {team_registration_id}")
            team_registration = TeamRegistration.objects.get(id=team_registration_id)
            if tournament_id and registration_type == 'cart' and team_registration.tournament is None:
                try:
                    tournament = Tournament.objects.get(id=tournament_id)
                    team_registration.tournament = tournament
                    team_registration.save()
                    print(f"Saved tournament for team registration {team_registration.id}")
                except Tournament.DoesNotExist:
                    print(f"Tournament not found with ID: {tournament_id}")
                except Exception as e:
                    print(f"Error saving tournament for team registration: {str(e)}")

            if team_registration.is_paid():
                return True

            team_registration.confirm_registration(checkout_session.payment_intent)

            TournamentEmailService.send_payment_confirmation(team_registration, checkout_session.payment_intent)
            return True
        except TeamRegistration.DoesNotExist:
            print(f"Team registration not found with ID: {team_registration_id}")
        except Exception as e:
            print(f"Error in _process_direct_payment: {str(e)}")
        return False

    @staticmethod
    @csrf_exempt
    @require_POST
    def stripe_webhook(request):
        payload = request.body
        sig_header = request.META.get('HTTP_STRIPE_SIGNATURE')
        print("Received webhook call")
        print(f"Signature: {sig_header}")

        try:
            event = stripe.Webhook.construct_event(
                payload, sig_header, settings.TOURNAMENT_STRIPE_WEBHOOK_SECRET
            )
            print(f"Tournament webhook event type: {event['type']}")

            stripe_object = event['data']['object']

            # Debug: Print the object type
            object_type = stripe_object.get('object', 'unknown')
            print(f"Stripe object type: {object_type}")

            if event['type'] == 'checkout.session.completed':
                success = PaymentService.process_direct_payment(stripe_object)
                if success:
                    print(f"Successfully processed completed checkout session")
                    return HttpResponse(status=200)
                else:
                    print(f"Failed to process completed checkout session")
                    return HttpResponse(status=400)

            elif event['type'] == 'payment_intent.payment_failed':
                success = PaymentService.process_failed_payment_intent(stripe_object)
                if success:
                    print(f"Successfully processed failed payment intent")
                    return HttpResponse(status=200)
                else:
                    print(f"Failed to process failed payment intent")
                    return HttpResponse(status=400)

            elif event['type'] == 'checkout.session.expired':
                success = PaymentService.process_expired_checkout_session(stripe_object)
                if success:
                    print(f"Successfully processed expired checkout session")
                    return HttpResponse(status=200)
                else:
                    print(f"Failed to process expired checkout session")
                    return HttpResponse(status=400)

            else:
                print(f"Unhandled event type: {event['type']}")
                return HttpResponse(status=200)

        except Exception as e:
            print(f"Tournament webhook error: {str(e)}")
            import traceback
            traceback.print_exc()
            return HttpResponse(status=400)
