"""
Authentication views for YOUR COMPANY CMS.

Login flow:
  Step 1 — credentials + reCAPTCHA v3 (hidden)
            If v3 score < threshold → escalate to v2 visual challenge
  Step 2 — 2FA code (TOTP / Email / SMS)
  Step 3 — session established, redirect to CMS dashboard
"""
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, logout, authenticate
from django.contrib import messages
from django.conf import settings

from .models import User, TwoFactorAuth
from .twofa import (
    verify_recaptcha_v3, verify_recaptcha_v2,
    send_email_otp, verify_email_otp,
    send_sms_otp, verify_sms_otp,
    verify_totp, verify_backup_code,
    mark_2fa_pending, get_2fa_pending_user, clear_2fa_pending,
)


# ─── Step 1: Login form ───────────────────────────────────────────────────────

def cms_login(request):
    if request.user.is_authenticated and request.user.is_cms_user:
        return redirect('cms_dashboard')

    if request.method == 'POST':
        username = request.POST.get('username', '').strip()
        password = request.POST.get('password', '').strip()
        v3_token = request.POST.get('g-recaptcha-response-v3', '')
        v2_token = request.POST.get('g-recaptcha-response-v2', '')
        needs_v2 = request.POST.get('needs_v2') == '1'

        # ── reCAPTCHA check ──────────────────────────────────────────────────
        if needs_v2:
            # User already saw the visual challenge
            if not verify_recaptcha_v2(v2_token):
                messages.error(request, 'Visual verification failed. Please try again.')
                return render(request, 'cms/login.html', _login_ctx(request, force_v2=True))
        else:
            # Hidden v3 check
            v3_ok, score = verify_recaptcha_v3(v3_token, action='cms_login')
            if not v3_ok:
                if score < 0.5 and _rc_v2_site_key():
                    # Escalate to visual challenge
                    return render(request, 'cms/login.html', _login_ctx(
                        request, force_v2=True,
                        username=username,
                        error='Please complete the security check below.'
                    ))
                messages.error(request, 'Verification failed. Please try again.')
                return render(request, 'cms/login.html', _login_ctx(request))

        # ── Authenticate ─────────────────────────────────────────────────────
        user = authenticate(request, username=username, password=password)
        if not user or not user.is_cms_user:
            messages.error(request, 'Invalid credentials or insufficient permissions.')
            return render(request, 'cms/login.html', _login_ctx(request, username=username))

        # ── 2FA check ────────────────────────────────────────────────────────
        if user.has_2fa:
            mark_2fa_pending(request, user.pk)
            # Auto-send code for email/SMS preferred method
            fa = user.two_fa
            if fa.preferred_method == TwoFactorAuth.METHOD_EMAIL:
                send_email_otp(user)
            elif fa.preferred_method == TwoFactorAuth.METHOD_SMS:
                send_sms_otp(user)
            return redirect('cms_2fa_verify')

        # No 2FA — log straight in
        login(request, user)
        return redirect(request.GET.get('next', 'cms_dashboard'))

    return render(request, 'cms/login.html', _login_ctx(request))


def _rc_site_key():
    from apps.pages.api_keys import get_recaptcha_site_key
    return get_recaptcha_site_key()


def _rc_v2_site_key():
    from apps.pages.api_keys import get_recaptcha_v2_site_key
    return get_recaptcha_v2_site_key()


def _login_ctx(request, force_v2=False, username='', error=None):
    ctx = {
        'recaptcha_v3_site_key': _rc_site_key(),
        'recaptcha_v2_site_key': _rc_v2_site_key(),
        'force_v2': force_v2,
        'username': username,
    }
    if error:
        ctx['recaptcha_error'] = error
    return ctx


# ─── Step 2: 2FA verification ─────────────────────────────────────────────────

def cms_2fa_verify(request):
    user_id = get_2fa_pending_user(request)
    if not user_id:
        messages.error(request, 'Session expired. Please log in again.')
        return redirect('cms_login')

    user = get_object_or_404(User, pk=user_id)
    fa = user.two_fa

    if request.method == 'POST':
        action = request.POST.get('action', 'verify')

        # ── Switch method ────────────────────────────────────────────────────
        if action == 'switch_method':
            new_method = request.POST.get('method')
            if new_method in fa.available_methods:
                fa.preferred_method = new_method
                fa.save(update_fields=['preferred_method'])
                if new_method == TwoFactorAuth.METHOD_EMAIL:
                    send_email_otp(user)
                elif new_method == TwoFactorAuth.METHOD_SMS:
                    send_sms_otp(user)
            return redirect('cms_2fa_verify')

        # ── Resend ───────────────────────────────────────────────────────────
        if action == 'resend':
            if fa.preferred_method == TwoFactorAuth.METHOD_EMAIL:
                send_email_otp(user)
                messages.success(request, 'Code resent to your email.')
            elif fa.preferred_method == TwoFactorAuth.METHOD_SMS:
                send_sms_otp(user)
                messages.success(request, 'Code resent via SMS.')
            return redirect('cms_2fa_verify')

        # ── Verify code ──────────────────────────────────────────────────────
        code = request.POST.get('code', '').strip().replace(' ', '').replace('-', '')
        verified = False

        if fa.preferred_method == TwoFactorAuth.METHOD_TOTP:
            verified = verify_totp(fa.totp_secret, code)
        elif fa.preferred_method == TwoFactorAuth.METHOD_EMAIL:
            verified = verify_email_otp(user, code)
        elif fa.preferred_method == TwoFactorAuth.METHOD_SMS:
            verified = verify_sms_otp(user, code)

        # Try backup code if normal code failed
        if not verified and len(code) > 6:
            verified = verify_backup_code(fa, code)

        if verified:
            from django.utils import timezone
            fa.last_used_at = timezone.now()
            fa.last_used_method = fa.preferred_method
            fa.save(update_fields=['last_used_at', 'last_used_method'])
            clear_2fa_pending(request)
            login(request, user)
            return redirect(request.GET.get('next', 'cms_dashboard'))

        messages.error(request, 'Invalid code. Please try again.')

    return render(request, 'cms/2fa_verify.html', {
        'user': user,
        'fa': fa,
        'method_label': dict(TwoFactorAuth.METHOD_CHOICES).get(fa.preferred_method, ''),
        'other_methods': [
            (m, dict(TwoFactorAuth.METHOD_CHOICES).get(m, m))
            for m in fa.available_methods
            if m != fa.preferred_method
        ],
    })


def cms_logout(request):
    logout(request)
    return redirect('home')
