"""
Business logic services for the enrollments app.
"""
from decimal import Decimal

from django.conf import settings as django_settings
from django.urls import reverse
from django.utils import timezone

from apps.enrollments.models import (
    Enrollment,
    PAYMENT_METHOD_FREE,
    PAYMENT_METHOD_MANUAL,
    PAYMENT_METHOD_STRIPE,
)


def enroll_student(student, course):
    """
    Create a new pending enrollment for a student.
    Raises ValueError if an active enrollment already exists.
    """
    existing = Enrollment.objects.filter(student=student, course=course).first()
    if existing:
        if existing.status in ('pending', 'approved'):
            raise ValueError("You already have an active or pending enrollment for this course.")
        # Allow re-enrollment if previously rejected
        existing.status = 'pending'
        existing.payment_method = ''
        existing.payment_proof = None
        existing.payment_note = ''
        existing.stripe_session_id = ''
        existing.stripe_payment_intent = ''
        existing.promo_code = None
        existing.original_amount = None
        existing.discount_amount = 0
        existing.payable_amount = None
        existing.requested_at = timezone.now()
        existing.rejection_reason = None
        existing.approved_at = None
        existing.approved_by = None
        existing.save()
        return existing

    enrollment = Enrollment.objects.create(
        student=student,
        course=course,
        status='pending'
    )
    return enrollment


def approve_enrollment(enrollment, admin_user=None):
    """Approve an enrollment (admin/teacher review or Stripe auto-activation)."""
    enrollment.status = 'approved'
    enrollment.approved_at = timezone.now()
    enrollment.approved_by = admin_user
    enrollment.rejection_reason = None
    enrollment.save()
    if enrollment.promo_code_id and enrollment.discount_amount:
        from apps.promotions.models import APPLIES_COURSES
        from apps.promotions.services import record_promo_redemption, enrollment_payable
        record_promo_redemption(
            promo=enrollment.promo_code,
            user=enrollment.student,
            scope=APPLIES_COURSES,
            original=enrollment.original_amount or enrollment.course.price,
            discount=enrollment.discount_amount,
            final=enrollment_payable(enrollment),
            enrollment=enrollment,
        )
    return enrollment


def activate_free_enrollment(enrollment):
    """Auto-approve free courses."""
    enrollment.payment_method = PAYMENT_METHOD_FREE
    return approve_enrollment(enrollment, admin_user=None)


def reject_enrollment(enrollment, admin_user, reason=''):
    """Reject an enrollment."""
    enrollment.status = 'rejected'
    enrollment.rejection_reason = reason
    enrollment.approved_by = admin_user
    enrollment.approved_at = timezone.now()
    enrollment.save()
    return enrollment


def get_pending_enrollments():
    """Return all pending enrollments."""
    return Enrollment.objects.filter(status='pending').select_related('student', 'course')


def get_student_enrollments(student):
    """Return all enrollments for a student."""
    return Enrollment.objects.filter(student=student).select_related('course')


def _amount_to_stripe_cents(amount, currency_code):
    """Convert Decimal amount to Stripe's smallest currency unit."""
    # Zero-decimal currencies (Stripe)
    zero_decimal = {
        'bif', 'clp', 'djf', 'gnf', 'jpy', 'kmf', 'krw', 'mga',
        'pyg', 'rwf', 'ugx', 'vnd', 'vuv', 'xaf', 'xof', 'xpf',
    }
    value = Decimal(amount or 0)
    if currency_code.lower() in zero_decimal:
        return int(value)
    return int(value * 100)


def create_stripe_checkout_session(enrollment, request):
    """
    Create a Stripe Checkout Session for a course enrollment.
    Returns the Session object (with .url for redirect).
    """
    import stripe
    from apps.dashboard.models import SiteSettings

    site = SiteSettings.load()
    if not site.stripe_ready:
        raise ValueError('Stripe is not configured. Ask the admin to enable it in Settings.')

    stripe.api_key = site.stripe_secret_key
    currency = (site.currency_code or 'PKR').lower()
    from apps.promotions.services import enrollment_payable
    amount = enrollment_payable(enrollment)
    if amount <= 0:
        raise ValueError('This course is free — no payment required.')

    success_url = request.build_absolute_uri(
        reverse('enrollments:stripe_success', kwargs={'pk': enrollment.pk})
    ) + '?session_id={CHECKOUT_SESSION_ID}'
    cancel_url = request.build_absolute_uri(
        reverse('enrollments:upload_payment', kwargs={'pk': enrollment.pk})
    )

    description = f'Course enrollment — {site.institute_name}'
    if enrollment.promo_code_id:
        description += f' (promo {enrollment.promo_code.code})'

    session = stripe.checkout.Session.create(
        mode='payment',
        customer_email=enrollment.student.email or None,
        line_items=[{
            'quantity': 1,
            'price_data': {
                'currency': currency,
                'unit_amount': _amount_to_stripe_cents(amount, currency),
                'product_data': {
                    'name': enrollment.course.title,
                    'description': description,
                },
            },
        }],
        metadata={
            'enrollment_id': str(enrollment.pk),
            'course_id': str(enrollment.course_id),
            'student_id': str(enrollment.student_id),
            'promo_code': enrollment.promo_code.code if enrollment.promo_code_id else '',
        },
        success_url=success_url,
        cancel_url=cancel_url,
    )

    enrollment.payment_method = PAYMENT_METHOD_STRIPE
    enrollment.stripe_session_id = session.id
    enrollment.save(update_fields=['payment_method', 'stripe_session_id'])
    return session


def finalize_stripe_enrollment(enrollment, session=None):
    """Mark enrollment paid/approved after successful Stripe Checkout."""
    if enrollment.status == 'approved':
        return enrollment

    enrollment.payment_method = PAYMENT_METHOD_STRIPE
    if session:
        enrollment.stripe_session_id = session.get('id') or enrollment.stripe_session_id
        payment_intent = session.get('payment_intent')
        if payment_intent:
            enrollment.stripe_payment_intent = (
                payment_intent if isinstance(payment_intent, str) else getattr(payment_intent, 'id', '')
            )
    return approve_enrollment(enrollment, admin_user=None)
