# subscriptions/views.py
"""
SaaS subscription views:
- Public: pricing, register
- Auth: choose_plan, checkout, payment_pending, payment_success
- Auth: manage (subscription management), billing_history
- Webhook: monnify_webhook (no auth, HMAC-verified)
"""
import json
import logging
from datetime import date

from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db import transaction as db_transaction
from django.http import HttpResponse, JsonResponse
from django.shortcuts import redirect, render, get_object_or_404
from django.urls import reverse
from django.utils.text import slugify
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST

from companies.models import Company, Plan, CompanySettings
from core.models import Branch
from accounts.models import CustomUser
from .models import Subscription, PaymentTransaction, SaasPromoCode
from .services import (
    create_trial_subscription,
    create_payment_intent,
    activate_subscription_for_transaction,
    validate_promo_code,
    calculate_subscription_amount,
    schedule_downgrade,
)
from . import monnify as monnify_client

logger = logging.getLogger(__name__)


# ─────────────────────────────────────────────────────────────
# PUBLIC PRICING PAGE
# ─────────────────────────────────────────────────────────────

def public_pricing(request):
    """Publicly visible pricing page. Shows all public, active plans."""
    plans = Plan.objects.filter(is_active=True, is_public=True).order_by('display_order', 'price_monthly')
    return render(request, 'subscriptions/pricing.html', {
        'plans': plans,
        'page_title': 'Pricing — SwiftPOS',
    })


# ─────────────────────────────────────────────────────────────
# COMPANY SELF-REGISTRATION
# ─────────────────────────────────────────────────────────────

def company_register(request):
    """
    Self-service company registration.
    Creates: Company + CompanySettings + main Branch + admin User + trial Subscription.
    """
    if request.user.is_authenticated:
        if request.user.is_superuser:
            return redirect('superadmin_company_list')
        company = getattr(request.user, 'company', None)
        if company:
            return redirect(f'/{company.slug}/dashboard/')

    plans = Plan.objects.filter(is_active=True, is_public=True).order_by('display_order', 'price_monthly')

    if request.method == 'POST':
        company_name = request.POST.get('company_name', '').strip()
        email        = request.POST.get('email', '').strip()
        phone        = request.POST.get('phone', '').strip()
        password     = request.POST.get('password', '').strip()
        password2    = request.POST.get('password2', '').strip()

        errors = []
        if not company_name:
            errors.append("Company name is required.")
        if not email:
            errors.append("Email is required.")
        if not password:
            errors.append("Password is required.")
        if len(password) < 8:
            errors.append("Password must be at least 8 characters.")
        if password != password2:
            errors.append("Passwords do not match.")

        slug = slugify(company_name)
        if not slug:
            errors.append("Company name produced an invalid URL slug.")
        elif Company.objects.filter(slug=slug).exists():
            errors.append(f"A company with this name already exists. Try adding your city or unique identifier.")

        if CustomUser.objects.filter(email=email).exists():
            errors.append("An account with this email already exists. Please log in.")

        if errors:
            for err in errors:
                messages.error(request, err)
            return render(request, 'subscriptions/register.html', {
                'plans': plans,
                'form_data': request.POST,
            })

        try:
            with db_transaction.atomic():
                # 1. Create company
                company = Company.objects.create(
                    name=company_name,
                    slug=slug,
                    email=email,
                    phone=phone,
                    is_active=True,
                )
                CompanySettings.objects.create(
                    company=company,
                    business_name=company_name,
                    business_email=email,
                    business_phone=phone,
                )

                # 2. Create main branch
                branch = Branch.objects.create(
                    company=company,
                    name="Main Branch",
                    code="MAIN",
                )

                # 3. Create admin user (username = email prefix or slugified name)
                username_base = email.split('@')[0].replace('.', '_').replace('+', '_')[:30]
                username = username_base
                # Ensure uniqueness
                counter = 1
                while CustomUser.objects.filter(username=username).exists():
                    username = f"{username_base}{counter}"
                    counter += 1

                user = CustomUser.objects.create_user(
                    username=username,
                    email=email,
                    password=password,
                    role='admin',
                    company=company,
                    branch=branch,
                    phone=phone,
                )

                # 4. Create trial subscription
                create_trial_subscription(company)

            # Auto-login
            login(request, user)
            messages.success(
                request,
                f"Welcome to SwiftPOS, {company_name}! "
                f"Your {getattr(settings, 'TRIAL_DURATION_DAYS', 3)}-day free trial has started."
            )
            return redirect(f'/{company.slug}/subscription/choose-plan/')

        except Exception as e:
            logger.error(f"Registration error: {e}", exc_info=True)
            messages.error(request, "Registration failed. Please try again or contact support.")
            return render(request, 'subscriptions/register.html', {
                'plans': plans,
                'form_data': request.POST,
            })

    return render(request, 'subscriptions/register.html', {
        'plans': plans,
    })


# ─────────────────────────────────────────────────────────────
# CHOOSE PLAN (post-login, post-trial)
# ─────────────────────────────────────────────────────────────

@login_required
def choose_plan(request):
    """
    Logged-in users can select/change their plan here.
    Also shown after trial expiry.
    """
    company = getattr(request, 'company', None)
    if not company:
        return redirect('login')

    plans = Plan.objects.filter(is_active=True, is_public=True).order_by('display_order', 'price_monthly')
    current_sub = Subscription.objects.filter(company=company, is_active=True).first()

    return render(request, 'subscriptions/choose_plan.html', {
        'plans': plans,
        'current_sub': current_sub,
        'page_title': 'Choose Your Plan — SwiftPOS',
    })


# ─────────────────────────────────────────────────────────────
# CHECKOUT
# ─────────────────────────────────────────────────────────────

@login_required
def checkout(request, plan_id):
    """
    Show checkout form: billing cycle selection + promo code.
    On POST: create Monnify payment intent and redirect to checkout URL.
    """
    company = getattr(request, 'company', None)
    if not company:
        return redirect('login')

    plan = get_object_or_404(Plan, id=plan_id, is_active=True)
    current_sub = Subscription.objects.filter(company=company, is_active=True).first()

    # Determine if this is an upgrade or downgrade
    action = 'subscribe'
    if current_sub and current_sub.plan:
        if plan.price_monthly > current_sub.plan.price_monthly:
            action = 'upgrade'
        elif plan.price_monthly < current_sub.plan.price_monthly:
            action = 'downgrade'
        else:
            action = 'renew'

    if request.method == 'POST':
        billing_cycle = request.POST.get('billing_cycle', 'monthly')
        promo_code    = request.POST.get('promo_code', '').strip()

        # Handle downgrade differently — no payment needed
        if action == 'downgrade':
            try:
                schedule_downgrade(company, plan)
                messages.success(
                    request,
                    f"Downgrade to {plan.name} scheduled. It will take effect when your current plan expires."
                )
                return redirect('subscriptions:manage')
            except Exception as e:
                messages.error(request, str(e))
                return redirect('subscriptions:choose_plan')

        # Build callback URLs — each gateway needs its own
        monnify_callback_url = request.build_absolute_uri(
            reverse('subscriptions:payment_callback')
        )
        paystack_callback_url = request.build_absolute_uri(
            reverse('subscriptions:paystack_callback')
        )
        # Legacy alias used by Monnify flow
        callback_url = monnify_callback_url

        is_ajax_request = request.headers.get('x-requested-with') == 'XMLHttpRequest'
        try:
            result = create_payment_intent(
                company=company,
                plan=plan,
                billing_cycle=billing_cycle,
                promo_code_str=promo_code,
                redirect_url=callback_url,
                use_frontend_sdk=is_ajax_request,
            )
            if is_ajax_request:
                # Completed free (100% promo discount)
                if result['transaction'].status == 'paid':
                    return JsonResponse({'ok': True, 'free': True, 'redirect_url': result['checkout_url']})

                admin_user = company.users.filter(role='admin').first()
                customer_email = (
                    (admin_user.email if admin_user else None)
                    or company.email
                    or getattr(settings, 'ADMIN_EMAIL', 'admin@swiftpos.ng')
                )

                gw = result.get('gateway', 'monnify')

                if gw == 'paystack':
                    # Paystack Inline v2: the JS SDK creates the transaction
                    # client-side using public key + reference. No server-side
                    # initialize_transaction() needed for inline popup mode.
                    txn = result['transaction']
                    return JsonResponse({
                        'ok': True,
                        'free': False,
                        'gateway': 'paystack',
                        'reference': txn.payment_reference,
                        'customer_name': company.name,
                        'customer_email': customer_email,
                        'amount': float(txn.final_amount),
                    })

                if gw == 'manual':
                    # Manual bank transfer: no SDK, just show bank details to the client
                    txn = result['transaction']
                    return JsonResponse({
                        'ok':          True,
                        'free':        False,
                        'gateway':     'manual',
                        'reference':   txn.payment_reference,
                        'amount':      float(txn.final_amount),
                        'bank_details': result.get('bank_details', {}),
                    })

                # Monnify inline SDK mode (unchanged)
                return JsonResponse({
                    'ok': True,
                    'free': False,
                    'gateway': 'monnify',
                    'amount': float(result['transaction'].final_amount),
                    'reference': result['transaction'].payment_reference,
                    'customer_name': company.name,
                    'customer_email': customer_email,
                })

            # Fallback: Redirect user to gateway hosted payment page if not AJAX
            return redirect(result['checkout_url'])
        except ValueError as e:
            logger.warning(f"Checkout validation error for {company.slug}: {e}")
            if is_ajax_request:
                return JsonResponse({'ok': False, 'message': str(e)}, status=400)
            messages.error(request, str(e))
        except Exception as e:
            logger.error(f"Checkout error for {company.slug}: {e}", exc_info=True)
            if is_ajax_request:
                return JsonResponse({'ok': False, 'message': 'Payment gateway error. Please try again.'}, status=500)
            messages.error(request, "Payment gateway error. Please try again.")

    # GET: show checkout form
    # Pre-calculate prices for all billing cycles
    billing_options = []
    for cycle_key, cycle_label in [
        ('monthly',    'Monthly'),
        ('bimonthly',  '2 Months'),
        ('trimonthly', '3 Months'),
        ('yearly',     'Yearly'),
    ]:
        price = plan.get_price_for_cycle(cycle_key)
        billing_options.append({
            'key':   cycle_key,
            'label': cycle_label,
            'price': price,
        })

    # Determine active gateway for template rendering
    from core.models import SiteConfiguration
    try:
        cfg = SiteConfiguration.get_solo()
        active_gateway = cfg.active_payment_gateway or 'monnify'
        # Expose manual bank details so template can display them (GET load)
        manual_bank_details = {
            'bank_name':      cfg.manual_bank_name,
            'account_number': cfg.manual_account_number,
            'account_name':   cfg.manual_account_name,
            'instructions':   cfg.manual_payment_instructions,
            'whatsapp_number': cfg.manual_whatsapp_number,
        } if active_gateway == 'manual' else {}
    except Exception:
        active_gateway = 'monnify'
        manual_bank_details = {}

    paystack_callback_url = request.build_absolute_uri(
        reverse('subscriptions:paystack_callback')
    )

    return render(request, 'subscriptions/checkout.html', {
        'plan': plan,
        'billing_options': billing_options,
        'action': action,
        'current_sub': current_sub,
        'page_title': f'Checkout — {plan.name} — SwiftPOS',
        'gateway': active_gateway,
        'manual_bank_details': manual_bank_details,
        'monnify_api_key': getattr(settings, 'MONNIFY_API_KEY', ''),
        'monnify_contract_code': getattr(settings, 'MONNIFY_CONTRACT_CODE', ''),
        'paystack_public_key': getattr(settings, 'PAYSTACK_PUBLIC_KEY', ''),
        'paystack_callback_url': paystack_callback_url,
    })


# ─────────────────────────────────────────────────────────────
# PROMO CODE AJAX VALIDATION
# ─────────────────────────────────────────────────────────────

@login_required
def validate_promo_ajax(request):
    """AJAX: validate promo code and return discount info."""
    if request.method != 'POST':
        return JsonResponse({'ok': False, 'message': 'Method not allowed'}, status=405)
    try:
        data = json.loads(request.body)
        code       = data.get('code', '').strip()
        plan_id    = data.get('plan_id')
        cycle      = data.get('billing_cycle', 'monthly')
    except Exception:
        return JsonResponse({'ok': False, 'message': 'Invalid request'}, status=400)

    try:
        plan = Plan.objects.get(id=plan_id, is_active=True)
    except Plan.DoesNotExist:
        return JsonResponse({'ok': False, 'message': 'Invalid plan'}, status=400)

    base_amount = calculate_subscription_amount(plan, cycle)
    try:
        promo, discount = validate_promo_code(code, plan, base_amount)
    except ValueError as e:
        return JsonResponse({'ok': False, 'message': str(e)})

    final = base_amount - discount
    return JsonResponse({
        'ok': True,
        'discount_amount': float(discount),
        'final_amount': float(final),
        'base_amount': float(base_amount),
        'message': f"Promo applied! You save ₦{discount:,.2f}",
    })


# ─────────────────────────────────────────────────────────────
# PAYMENT CALLBACK (Monnify redirects user here after payment)
# ─────────────────────────────────────────────────────────────

@login_required
def payment_callback(request):
    """
    Monnify redirects here after the user completes/cancels payment.
    We verify the transaction status before showing success.
    """
    company = getattr(request, 'company', None)
    payment_reference = request.GET.get('paymentReference', '')

    if not payment_reference:
        messages.warning(request, "Payment reference not found. Your payment may still be processing.")
        return redirect('subscriptions:manage')

    try:
        txn = PaymentTransaction.objects.get(
            payment_reference=payment_reference,
            company=company,
        )
    except PaymentTransaction.DoesNotExist:
        messages.error(request, "Transaction not found.")
        return redirect('subscriptions:manage')

    # If transaction was already marked as paid (e.g. Free plan bypass) 
    if txn.status == 'paid':
        messages.success(request, f"🎉 Payment successful! Your {txn.plan.name} plan is now active.")
        return render(request, 'subscriptions/payment_success.html', {
            'txn': txn,
            'company': company,
        })

    # Route verification to the correct gateway that processed this transaction
    try:
        gateway = getattr(txn, 'gateway', None) or 'monnify'

        if gateway == 'paystack':
            from . import paystack as paystack_client
            ps_data = paystack_client.verify_transaction(payment_reference)
            pay_status = ps_data.get('status', '').lower()
            if pay_status == 'success':
                txn.raw_webhook_payload = ps_data
                txn.payment_method = ps_data.get('channel', '')
                txn.save(update_fields=['raw_webhook_payload', 'payment_method'])
                activate_subscription_for_transaction(txn)
                messages.success(request, f"Payment successful! Your {txn.plan.name} plan is now active.")
                return render(request, 'subscriptions/payment_success.html', {'txn': txn, 'company': company})
            else:
                return render(request, 'subscriptions/payment_pending.html', {
                    'txn': txn,
                    'payment_status': pay_status.upper(),
                })
        else:  # monnify
            monnify_data = monnify_client.verify_transaction(payment_reference)
            payment_status = monnify_data.get('paymentStatus', '').upper()
            if payment_status == 'PAID':
                txn.raw_webhook_payload = monnify_data
                activate_subscription_for_transaction(txn)
                messages.success(request, f"Payment successful! Your {txn.plan.name} plan is now active.")
                return render(request, 'subscriptions/payment_success.html', {'txn': txn, 'company': company})
            else:
                txn.status = 'pending'
                txn.save(update_fields=['status'])
                return render(request, 'subscriptions/payment_pending.html', {
                    'txn': txn,
                    'payment_status': payment_status,
                })
    except Exception as e:
        logger.error(f"Payment callback verification error: {e}", exc_info=True)
        return render(request, 'subscriptions/payment_pending.html', {
            'txn': txn,
            'payment_status': 'UNKNOWN',
        })


# ─────────────────────────────────────────────────────────────
# MONNIFY WEBHOOK (HMAC-verified, no CSRF, no auth)
# ─────────────────────────────────────────────────────────────

@csrf_exempt
@require_POST
def monnify_webhook(request):
    """
    Monnify sends payment notifications here.
    Validates HMAC signature, then activates subscription.
    """
    # 1. Validate HMAC signature
    sig = request.headers.get('monnify-signature', '')
    raw_body = request.body

    if not monnify_client.validate_webhook_signature(raw_body, sig):
        logger.warning(f"Invalid Monnify webhook signature from {request.META.get('REMOTE_ADDR')}")
        return HttpResponse("Invalid signature", status=400)

    # 2. Parse payload
    try:
        payload = json.loads(raw_body)
    except json.JSONDecodeError:
        return HttpResponse("Invalid JSON", status=400)

    event_type = payload.get('eventType', '')
    data = payload.get('eventData', {})

    if event_type != 'SUCCESSFUL_TRANSACTION':
        # Ignore non-payment events (just acknowledge)
        return HttpResponse("OK", status=200)

    payment_reference = data.get('paymentReference', '')
    monnify_ref = data.get('transactionReference', '')
    payment_status = data.get('paymentStatus', '').upper()

    if payment_status != 'PAID':
        logger.info(f"Monnify webhook: non-paid status={payment_status} ref={payment_reference}")
        return HttpResponse("OK", status=200)

    # 3. Find transaction
    try:
        txn = PaymentTransaction.objects.select_related('company', 'plan').get(
            payment_reference=payment_reference,
        )
    except PaymentTransaction.DoesNotExist:
        logger.error(f"Monnify webhook: transaction not found for ref={payment_reference}")
        return HttpResponse("Transaction not found", status=404)

    # 4. Double-processing guard
    if txn.status == 'paid':
        return HttpResponse("Already processed", status=200)

    # 5. Activate
    try:
        txn.monnify_reference = monnify_ref
        txn.payment_method = data.get('paymentMethod', '')
        txn.raw_webhook_payload = payload
        txn.save(update_fields=['monnify_reference', 'payment_method', 'raw_webhook_payload'])
        activate_subscription_for_transaction(txn)
        logger.info(f"✅ Webhook activated subscription for company={txn.company.slug}")
    except Exception as e:
        logger.error(f"Webhook activation error: {e}", exc_info=True)
        return HttpResponse("Activation error", status=500)

    return HttpResponse("OK", status=200)


# ─────────────────────────────────────────────────────────────
# SUBSCRIPTION MANAGEMENT
# ─────────────────────────────────────────────────────────────

@login_required
def subscription_manage(request):
    """Company admin: view current subscription, usage, and options."""
    company = getattr(request, 'company', None)
    if not company:
        return redirect('login')

    current_sub = Subscription.objects.filter(company=company, is_active=True).first()
    plans = Plan.objects.filter(is_active=True, is_public=True).order_by('display_order', 'price_monthly')

    # Recent transactions
    transactions = PaymentTransaction.objects.filter(company=company).order_by('-created_at')[:5]

    return render(request, 'subscriptions/manage.html', {
        'current_sub': current_sub,
        'company': company,
        'plans': plans,
        'transactions': transactions,
        'page_title': 'Subscription — SwiftPOS',
        'trial_days': getattr(settings, 'TRIAL_DURATION_DAYS', 3),
    })


# ─────────────────────────────────────────────────────────────
# BILLING HISTORY
# ─────────────────────────────────────────────────────────────

@login_required
def billing_history(request):
    """Paginated list of all payment transactions for this company."""
    company = getattr(request, 'company', None)
    if not company:
        return redirect('login')

    txn_qs = PaymentTransaction.objects.filter(company=company).order_by('-created_at')
    paginator = Paginator(txn_qs, 20)
    page_obj = paginator.get_page(request.GET.get('page'))

    return render(request, 'subscriptions/billing_history.html', {
        'page_obj': page_obj,
        'company': company,
        'page_title': 'Billing History — SwiftPOS',
    })


# ---------------------------------------------------------
# PAYSTACK WEBHOOK  (HMAC-SHA512 verified, no CSRF/auth)
# ---------------------------------------------------------

@csrf_exempt
@require_POST
def paystack_webhook(request):
    """
    Paystack sends payment events here.
    Validates HMAC-SHA512 signature then activates subscription.
    """
    from . import paystack as paystack_client

    sig = request.headers.get('x-paystack-signature', '')
    raw_body = request.body

    if not paystack_client.validate_webhook_signature(raw_body, sig):
        logger.warning(f"Invalid Paystack signature from {request.META.get('REMOTE_ADDR')}")
        return HttpResponse("Invalid signature", status=400)

    try:
        payload = json.loads(raw_body)
    except json.JSONDecodeError:
        return HttpResponse("Invalid JSON", status=400)

    event = payload.get('event', '')
    if event != 'charge.success':
        return HttpResponse("OK", status=200)  # Ack non-payment events

    data = payload.get('data', {})
    reference = data.get('reference', '')
    pay_status = data.get('status', '').lower()

    if pay_status != 'success':
        logger.info(f"Paystack webhook non-success status={pay_status} ref={reference}")
        return HttpResponse("OK", status=200)

    try:
        txn = PaymentTransaction.objects.select_related('company', 'plan').get(
            payment_reference=reference,
        )
    except PaymentTransaction.DoesNotExist:
        logger.error(f"Paystack webhook: transaction not found ref={reference}")
        return HttpResponse("Not found", status=404)

    if txn.status == 'paid':
        return HttpResponse("Already processed", status=200)

    try:
        txn.gateway_reference = data.get('id', '')
        txn.payment_method    = data.get('channel', '')
        txn.raw_webhook_payload = payload
        txn.save(update_fields=['gateway_reference', 'payment_method', 'raw_webhook_payload'])
        activate_subscription_for_transaction(txn)
        logger.info(f"Paystack webhook activated subscription for company={txn.company.slug}")
    except Exception as e:
        logger.error(f"Paystack webhook activation error: {e}", exc_info=True)
        return HttpResponse("Activation error", status=500)

    return HttpResponse("OK", status=200)


# ---------------------------------------------------------
# PAYSTACK PAYMENT CALLBACK (Paystack redirects user here)
# ---------------------------------------------------------

@login_required
def paystack_callback(request):
    """
    Paystack redirects here after payment (with ?reference= in URL).
    Verifies server-side then activates subscription.
    """
    from . import paystack as paystack_client

    company = getattr(request, 'company', None)
    reference = request.GET.get('reference', '') or request.GET.get('paymentReference', '')

    if not reference:
        messages.warning(request, "Payment reference not found.")
        return redirect('subscriptions:manage')

    try:
        txn = PaymentTransaction.objects.get(payment_reference=reference, company=company)
    except PaymentTransaction.DoesNotExist:
        messages.error(request, "Transaction not found.")
        return redirect('subscriptions:manage')

    if txn.status == 'paid':
        messages.success(request, f"Payment successful! Your {txn.plan.name} plan is now active.")
        return render(request, 'subscriptions/payment_success.html', {'txn': txn, 'company': company})

    try:
        ps_data = paystack_client.verify_transaction(reference)
        if ps_data.get('status') == 'success':
            txn.raw_webhook_payload = ps_data
            txn.payment_method = ps_data.get('channel', '')
            txn.save(update_fields=['raw_webhook_payload', 'payment_method'])
            activate_subscription_for_transaction(txn)
            messages.success(request, f"Payment successful! Your {txn.plan.name} plan is now active.")
            return render(request, 'subscriptions/payment_success.html', {'txn': txn, 'company': company})
        else:
            return render(request, 'subscriptions/payment_pending.html', {
                'txn': txn, 'payment_status': ps_data.get('status', 'UNKNOWN').upper()
            })
    except Exception as e:
        logger.error(f"Paystack callback error: {e}", exc_info=True)
        return render(request, 'subscriptions/payment_pending.html', {'txn': txn, 'payment_status': 'UNKNOWN'})


# ─────────────────────────────────────────────────────────────
# MANUAL PAYMENT CONFIRMATION  (Superadmin/Admin only)
# ─────────────────────────────────────────────────────────────

@login_required
def admin_mark_manual_paid(request, reference):
    """
    Superadmin-only endpoint to confirm a manual bank transfer and activate
    the corresponding pending subscription.
    
    GET  → confirmation page
    POST → mark paid + activate subscription
    """
    if not (request.user.is_superuser or getattr(request.user, 'role', '') == 'admin'):
        from django.http import HttpResponseForbidden
        return HttpResponseForbidden("Superadmin or admin access required.")

    try:
        txn = PaymentTransaction.objects.select_related('company', 'plan').get(
            payment_reference=reference
        )
    except PaymentTransaction.DoesNotExist:
        messages.error(request, f"Transaction '{reference}' not found.")
        return redirect('subscriptions:billing_history')

    if txn.status == 'paid':
        messages.info(request, f"Transaction {reference} is already marked as paid.")
        return redirect('subscriptions:billing_history')

    if request.method == 'POST':
        try:
            txn.gateway = 'manual'
            txn.payment_method = 'Manual Bank Transfer'
            txn.save(update_fields=['gateway', 'payment_method'])
            activate_subscription_for_transaction(txn)
            messages.success(
                request,
                f"✅ Payment confirmed! Subscription for '{txn.company.name}' ({txn.plan.name}) is now active."
            )
            logger.info(
                f"[manual_payment] Superadmin {request.user.username} confirmed "
                f"manual payment {reference} for company={txn.company.slug}"
            )
        except Exception as e:
            logger.error(f"[manual_payment] Activation error for {reference}: {e}", exc_info=True)
            messages.error(request, f"Activation failed: {e}")
        return redirect('subscriptions:billing_history')

    # GET — show confirmation page
    return render(request, 'subscriptions/confirm_manual_payment.html', {
        'txn': txn,
        'page_title': 'Confirm Manual Payment — SwiftPOS',
    })
