import hmac
import hashlib
import uuid
import json
import requests

from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.utils.timezone import now, timedelta

from .models import (
    Organization, Coupon, Payment, Subscription,
    PLAN_LIMITS, PLAN_CHOICES, GST_PERCENT, PlatformSettings
)


# ------------------------------------------------------------------ #
# HELPERS
# ------------------------------------------------------------------ #
def calculate_amounts(plan, coupon_obj=None):
    """
    Returns dict with original, discount, after_discount, gst, total.
    All amounts in INR (integers).
    """
    original = PLAN_LIMITS[plan]['price']

    discount = 0
    if coupon_obj:
        discount = int(coupon_obj.calculate_discount(original))

    after_discount = original - discount
    gst            = round((after_discount * GST_PERCENT) / 100)
    total          = after_discount + gst

    return {
        'original':       original,
        'discount':       discount,
        'after_discount': after_discount,
        'gst':            gst,
        'total':          total,
    }


# ------------------------------------------------------------------ #
# STEP 1 — UPGRADE PAGE (plan selection)
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def upgrade(request):
    org = request.user.org
    if not org:
        return redirect('landing')

    if request.method == 'POST':
        selected_plan = request.POST.get('plan', '')
        if selected_plan not in ('starter', 'business', 'enterprise'):
            from django.contrib import messages
            messages.error(request, 'Invalid plan selected.')
            return render(request, 'accounts/upgrade.html', {
                'org': org, 'plans': PLAN_LIMITS
            })
        return redirect('payment_page', plan=selected_plan)

    return render(request, 'accounts/upgrade.html', {
        'org':   org,
        'plans': PLAN_LIMITS,
    })


# ------------------------------------------------------------------ #
# STEP 2 — PAYMENT PAGE (coupon + cashfree)
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def payment_page(request, plan):
    org = request.user.org
    if not org:
        return redirect('landing')

    if plan not in ('starter', 'business', 'enterprise'):
        return redirect('upgrade')

    amounts = calculate_amounts(plan)
    platform = PlatformSettings.get_solo()

    return render(request, 'accounts/payment.html', {
        'org':          org,
        'plan':         plan,
        'plan_display': plan.title(),
        'amounts':      amounts,
        'plan_limits':  PLAN_LIMITS[plan],
        'cashfree_env': getattr(settings, 'CASHFREE_ENV', 'sandbox'),
        'gateway_enabled': platform.payment_gateway_enabled,
        'support_email':   platform.support_email,
    })


# ------------------------------------------------------------------ #
# AJAX — APPLY COUPON
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def apply_coupon(request):
    if request.method != 'POST':
        return JsonResponse({'success': False, 'error': 'Invalid request.'})

    code = request.POST.get('code', '').strip().upper()
    plan = request.POST.get('plan', '')

    if not code:
        return JsonResponse({'success': False, 'error': 'Please enter a coupon code.'})

    try:
        coupon = Coupon.objects.get(code=code)
    except Coupon.DoesNotExist:
        return JsonResponse({'success': False, 'error': 'Invalid coupon code.'})

    is_valid, message = coupon.is_valid(plan=plan)
    if not is_valid:
        return JsonResponse({'success': False, 'error': message})

    amounts = calculate_amounts(plan, coupon_obj=coupon)

    return JsonResponse({
        'success':        True,
        'message':        f'Coupon applied! You save ₹{amounts["discount"]}.',
        'discount_type':  coupon.get_discount_type_display(),
        'original':       amounts['original'],
        'discount':       amounts['discount'],
        'after_discount': amounts['after_discount'],
        'gst':            amounts['gst'],
        'total':          amounts['total'],
        'is_free':        amounts['total'] == 0,
    })


# ------------------------------------------------------------------ #
# STEP 3a — CREATE CASHFREE ORDER (AJAX)
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def create_cashfree_order(request):
    if request.method != 'POST':
        return JsonResponse({'success': False, 'error': 'Invalid request.'})

    org         = request.user.org
    plan        = request.POST.get('plan', '')
    coupon_code = request.POST.get('coupon_code', '').strip().upper()

    if plan not in ('starter', 'business', 'enterprise'):
        return JsonResponse({'success': False, 'error': 'Invalid plan.'})

    if not PlatformSettings.get_solo().payment_gateway_enabled:
        return JsonResponse({
            'success': False,
            'error':   'Online payments are currently disabled. Please use a coupon code or contact the administrator.'
        })

    coupon_obj = None
    if coupon_code:
        try:
            coupon_obj = Coupon.objects.get(code=coupon_code)
            is_valid, msg = coupon_obj.is_valid(plan=plan)
            if not is_valid:
                return JsonResponse({'success': False, 'error': msg})
        except Coupon.DoesNotExist:
            return JsonResponse({'success': False, 'error': 'Invalid coupon code.'})

    amounts = calculate_amounts(plan, coupon_obj)

    # If total is 0 (100% free coupon) — skip payment gateway
    if amounts['total'] == 0:
        return JsonResponse({
            'success':  True,
            'is_free':  True,
            'plan':     plan,
            'coupon':   coupon_code,
        })

    # Create payment record (pending)
    order_id = f"AVG-{uuid.uuid4().hex[:12].upper()}"

    payment = Payment.objects.create(
        org              = org,
        plan             = plan,
        original_amount  = amounts['original'],
        discount_amount  = amounts['discount'],
        gst_amount       = amounts['gst'],
        final_amount     = amounts['total'],
        coupon           = coupon_obj,
        gateway          = 'cashfree',
        gateway_order_id = order_id,
        status           = 'pending',
    )

    # Cashfree API — Create Order
    cf_env = getattr(settings, 'CASHFREE_ENV', 'sandbox')
    base_url = (
        'https://sandbox.cashfree.com/pg'
        if cf_env == 'sandbox'
        else 'https://api.cashfree.com/pg'
    )

    payload = {
        'order_id':       order_id,
        'order_amount':   amounts['total'],
        'order_currency': 'INR',
        'customer_details': {
            'customer_id':    str(org.id),
            'customer_email': org.email,
            'customer_phone': org.phone or '9999999999',
            'customer_name':  request.user.name,
        },
        'order_meta': {
            'return_url': f"{settings.SITE_URL}/payment/success/?order_id={order_id}",
            'notify_url': f"{settings.SITE_URL}/payment/webhook/",
        },
        'order_note': f"Avighna Solution — {plan.title()} Plan",
    }

    headers = {
        'Content-Type':  'application/json',
        'x-api-version': '2023-08-01',
        'x-client-id':   settings.CASHFREE_APP_ID,
        'x-client-secret': settings.CASHFREE_SECRET_KEY,
    }

    try:
        response = requests.post(
            f'{base_url}/orders',
            json    = payload,
            headers = headers,
            timeout = 10,
        )
        data = response.json()

        if response.status_code != 200 or 'payment_session_id' not in data:
            payment.status = 'failed'
            payment.notes  = str(data)
            payment.save()
            return JsonResponse({
                'success': False,
                'error':   data.get('message', 'Failed to create payment order.')
            })

        # Save session ID
        payment.notes = data.get('payment_session_id', '')
        payment.save(update_fields=['notes'])

        return JsonResponse({
            'success':            True,
            'is_free':            False,
            'payment_session_id': data['payment_session_id'],
            'order_id':           order_id,
            'amount':             amounts['total'],
        })

    except requests.exceptions.RequestException as e:
        payment.status = 'failed'
        payment.notes  = str(e)
        payment.save()
        return JsonResponse({'success': False, 'error': 'Payment gateway connection failed. Please try again.'})


# ------------------------------------------------------------------ #
# STEP 3b — FREE PLAN ACTIVATION (coupon = 100% off)
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def activate_free_plan(request):
    if request.method != 'POST':
        return redirect('upgrade')

    org         = request.user.org
    plan        = request.POST.get('plan', '')
    coupon_code = request.POST.get('coupon_code', '').strip().upper()

    if plan not in ('starter', 'business', 'enterprise'):
        return redirect('upgrade')

    coupon_obj = None
    if coupon_code:
        try:
            coupon_obj = Coupon.objects.get(code=coupon_code)
            is_valid, msg = coupon_obj.is_valid(plan=plan)
            if not is_valid:
                from django.contrib import messages
                messages.error(request, msg)
                return redirect('payment_page', plan=plan)
        except Coupon.DoesNotExist:
            from django.contrib import messages
            messages.error(request, 'Invalid coupon code.')
            return redirect('payment_page', plan=plan)

    amounts = calculate_amounts(plan, coupon_obj)

    if amounts['total'] != 0:
        return redirect('payment_page', plan=plan)

    # Record payment as free
    Payment.objects.create(
        org             = org,
        plan            = plan,
        original_amount = amounts['original'],
        discount_amount = amounts['discount'],
        gst_amount      = 0,
        final_amount    = 0,
        coupon          = coupon_obj,
        gateway         = 'free_coupon',
        status          = 'success',
        notes           = f'100% discount via coupon {coupon_code}.',
    )

    if coupon_obj:
        coupon_obj.apply()

    # Activate plan
    org.activate_plan(plan)

    Subscription.objects.create(
        org        = org,
        plan       = plan,
        status     = 'active',
        amount     = 0,
        start_date = org.plan_start,
        end_date   = org.plan_end,
        notes      = f'Activated free via coupon {coupon_code}.',
    )

    from django.contrib import messages
    messages.success(request, f'{plan.title()} plan activated for free using coupon {coupon_code}!')
    return redirect('dashboard')


# ------------------------------------------------------------------ #
# STEP 4 — PAYMENT SUCCESS (return URL from Cashfree)
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def payment_success(request):
    order_id = request.GET.get('order_id', '')
    org      = request.user.org

    if not order_id or not org:
        return redirect('dashboard')

    try:
        payment = Payment.objects.get(gateway_order_id=order_id, org=org)
    except Payment.DoesNotExist:
        return redirect('dashboard')

    # Verify payment status with Cashfree
    cf_env   = getattr(settings, 'CASHFREE_ENV', 'sandbox')
    base_url = (
        'https://sandbox.cashfree.com/pg'
        if cf_env == 'sandbox'
        else 'https://api.cashfree.com/pg'
    )

    headers = {
        'x-api-version':   '2023-08-01',
        'x-client-id':     settings.CASHFREE_APP_ID,
        'x-client-secret': settings.CASHFREE_SECRET_KEY,
    }

    try:
        response = requests.get(
            f'{base_url}/orders/{order_id}/payments',
            headers = headers,
            timeout = 10,
        )
        data = response.json()

        # Check if any payment is SUCCESS
        cf_status = None
        if isinstance(data, list) and data:
            cf_status = data[0].get('payment_status', '')
        elif isinstance(data, dict):
            cf_status = data.get('payment_status', '')

        if cf_status == 'SUCCESS':
            _activate_after_payment(payment, data[0] if isinstance(data, list) else data)
            return render(request, 'accounts/payment_success.html', {
                'org':    org,
                'plan':   payment.plan,
                'amount': payment.final_amount,
            })
        else:
            payment.status = 'failed'
            payment.save(update_fields=['status'])
            return render(request, 'accounts/payment_failed.html', {
                'org': org, 'plan': payment.plan
            })

    except Exception as e:
        # Fallback for sandbox / connectivity issues
        return render(request, 'accounts/payment_success.html', {
            'org':    org,
            'plan':   payment.plan,
            'amount': payment.final_amount,
        })


def _activate_after_payment(payment, cf_data=None):
    """Activate plan after successful payment verification."""
    if payment.status == 'success':
        return  # Already activated

    if cf_data:
        payment.gateway_payment_id = cf_data.get('cf_payment_id', '')
        payment.payment_method     = cf_data.get('payment_group', '')

    payment.status = 'success'
    payment.save()

    # Apply coupon usage
    if payment.coupon:
        payment.coupon.apply()

    # Activate plan
    org = payment.org
    org.activate_plan(payment.plan)

    # Create subscription record
    Subscription.objects.create(
        org        = org,
        plan       = payment.plan,
        status     = 'active',
        amount     = payment.final_amount,
        start_date = org.plan_start,
        end_date   = org.plan_end,
        notes      = f'Payment ID: {payment.gateway_payment_id}',
    )


# ------------------------------------------------------------------ #
# WEBHOOK — Cashfree server-to-server notification
# ------------------------------------------------------------------ #
@csrf_exempt
def payment_webhook(request):
    if request.method != 'POST':
        return JsonResponse({'status': 'error'}, status=400)

    try:
        body      = request.body.decode('utf-8')
        signature = request.headers.get('x-webhook-signature', '')
        timestamp = request.headers.get('x-webhook-timestamp', '')

        # Verify webhook signature
        secret    = settings.CASHFREE_SECRET_KEY
        raw       = timestamp + body
        expected  = hmac.new(
            secret.encode('utf-8'),
            raw.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()

        if not hmac.compare_digest(expected, signature):
            return JsonResponse({'status': 'invalid signature'}, status=400)

        data      = json.loads(body)
        event     = data.get('type', '')
        order_id  = data.get('data', {}).get('order', {}).get('order_id', '')

        if event == 'PAYMENT_SUCCESS_WEBHOOK' and order_id:
            try:
                payment  = Payment.objects.get(gateway_order_id=order_id)
                cf_data  = data.get('data', {}).get('payment', {})
                _activate_after_payment(payment, cf_data)
            except Payment.DoesNotExist:
                pass

        return JsonResponse({'status': 'ok'})

    except Exception as e:
        return JsonResponse({'status': 'error', 'detail': str(e)}, status=500)


# ------------------------------------------------------------------ #
# PAYMENT HISTORY (for client)
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def payment_history(request):
    org      = request.user.org
    payments = Payment.objects.filter(org=org).order_by('-created_at')
    return render(request, 'accounts/payment_history.html', {
        'org':      org,
        'payments': payments,
    })
