from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import Http404, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views.decorators.http import require_POST

from .dpo_client import DPOClient
from .models import PaymentMethod, SubscriptionPayment, SubscriptionPlan
from .payment_service import (
    create_pending_payment,
    generate_txn_reference,
    plan_allowed_for_user,
    reject_subscription_payment,
    verify_pending_payment,
)


def _payment_configured():
    return bool(getattr(settings, 'DPO_COMPANY_TOKEN', ''))


def _normalize_zambia_phone(phone_num):
    clean_phone = ''.join(filter(str.isdigit, phone_num or ''))
    if clean_phone.startswith('0'):
        return '260' + clean_phone[1:]
    if not clean_phone.startswith('260'):
        return '260' + clean_phone
    return clean_phone


def pricing_view(request):
    C = SubscriptionPlan.Category
    base = SubscriptionPlan.objects.filter(is_active=True)
    return render(request, 'subscriptions/pricing.html', {
        'seeker_plans': base.filter(audience=SubscriptionPlan.Audience.SEEKER, category=C.MEMBERSHIP),
        'recruitment_plans': base.filter(audience=SubscriptionPlan.Audience.COMPANY, category=C.RECRUITMENT),
        'talent_plans': base.filter(audience=SubscriptionPlan.Audience.COMPANY, category=C.TALENT_DATABASE),
    })


@login_required
def pay_view(request, slug):
    plan = get_object_or_404(SubscriptionPlan, slug=slug, is_active=True)
    if plan.price_monthly == 0:
        messages.info(request, 'This plan is free - no payment is required.')
        return redirect('subscriptions:pricing')
    if not plan_allowed_for_user(plan, request.user):
        messages.error(request, 'This plan is not available for your account type.')
        return redirect('subscriptions:pricing')

    return render(request, 'subscriptions/pay.html', {
        'plan': plan,
        'payment_methods': PaymentMethod.objects.filter(is_active=True),
        'payment_configured': _payment_configured(),
    })


@login_required
@require_POST
def submit_payment(request, slug):
    plan = get_object_or_404(SubscriptionPlan, slug=slug, is_active=True)
    if not plan_allowed_for_user(plan, request.user):
        raise Http404
    if not _payment_configured():
        messages.error(request, 'Online payments are not configured yet. Contact support to activate your plan.')
        return redirect('subscriptions:pay', slug=slug)

    payment_option = request.POST.get('payment_option')
    txn_reference = generate_txn_reference(request.user.pk, plan.pk)
    status_url = request.build_absolute_uri(
        reverse('subscriptions:payment_status', kwargs={'txn': txn_reference})
    )
    back_url = request.build_absolute_uri(reverse('subscriptions:pay', kwargs={'slug': slug}))
    amount = plan.price_monthly
    currency = 'ZMW'

    if payment_option == 'mobile_money':
        network = request.POST.get('network')
        phone_num = _normalize_zambia_phone(request.POST.get('phone_num'))
        if not network or not phone_num:
            messages.error(request, 'Select a network and enter your mobile money number.')
            return redirect('subscriptions:pay', slug=slug)

        result = DPOClient.charge_mobile_money(
            company_ref=txn_reference,
            amount=amount,
            currency=currency,
            redirect_url=status_url,
            back_url=back_url,
            service_description=f'{plan.name} subscription',
            customer_first_name=request.user.first_name or 'Customer',
            customer_last_name=request.user.last_name or 'User',
            customer_email=request.user.email,
            customer_phone=phone_num,
            customer_country='ZM',
            customer_city='Lusaka',
            network=network,
            mobile_phone=phone_num,
        )
        payment = create_pending_payment(
            request.user, plan, 'mobile_money', txn_reference, result.get('token') or ''
        )
        if result.get('success'):
            return redirect('subscriptions:payment_status', txn=txn_reference)
        reject_subscription_payment(payment)
        messages.error(request, result.get('message', 'Mobile money payment failed.'))
        return redirect('subscriptions:pay', slug=slug)

    if payment_option == 'card':
        token_root = DPOClient.create_charge_token(
            company_ref=txn_reference,
            amount=amount,
            currency=currency,
            redirect_url=status_url,
            back_url=back_url,
            service_description=f'{plan.name} subscription',
            customer_first_name=request.user.first_name or 'Customer',
            customer_last_name=request.user.last_name or 'User',
            customer_email=request.user.email,
            customer_phone=getattr(request.user, 'phone', '') or '260000000000',
            customer_country='ZM',
            customer_city='Lusaka',
        )
        result_code = token_root.find('Result')
        if result_code is None or result_code.text != '000':
            explanation = token_root.find('ResultExplanation')
            messages.error(
                request,
                explanation.text if explanation is not None else 'Could not start card payment.',
            )
            return redirect('subscriptions:pay', slug=slug)

        transaction_token = token_root.find('TransToken').text
        create_pending_payment(request.user, plan, 'card', txn_reference, transaction_token)
        return redirect(DPOClient.hosted_checkout_url(transaction_token))

    messages.error(request, 'Choose a valid payment method.')
    return redirect('subscriptions:pay', slug=slug)


@login_required
def payment_status(request, txn):
    payment = get_object_or_404(
        SubscriptionPayment,
        txn_reference=txn,
        user=request.user,
    )
    if payment.status == SubscriptionPayment.Status.PAID:
        return redirect('subscriptions:payment_success')
    if payment.status == SubscriptionPayment.Status.REJECTED:
        return redirect('subscriptions:payment_cancel')
    if not payment.provider_reference:
        messages.error(request, 'Payment reference missing.')
        return redirect('subscriptions:pricing')

    method_slug = ''
    if payment.payment_method_id:
        method_slug = payment.payment_method.slug

    return render(request, 'subscriptions/payment_status.html', {
        'payment': payment,
        'txn': txn,
        'method_slug': method_slug,
    })


@login_required
def payment_status_poll(request, txn):
    payment = get_object_or_404(
        SubscriptionPayment,
        txn_reference=txn,
        user=request.user,
    )
    status = verify_pending_payment(payment)
    return JsonResponse({'tran_status': status})


@login_required
def payment_success(request):
    return render(request, 'subscriptions/payment_success.html')


@login_required
def payment_cancel(request):
    messages.info(request, 'Payment was cancelled. You can try again when ready.')
    return redirect('subscriptions:pricing')
