from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.utils.text import slugify
from django.utils.timezone import now, timedelta
from django.http import JsonResponse
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from .models import Organization, User, Subscription, OTPVerification, SECTOR_CHOICES, PLAN_LIMITS, TRIAL_DAYS, PlatformSettings, VERIFICATION_FIELD_CHOICES, VERIFICATION_FIELD_LABELS, default_verification_fields, Payment
from .email_utils import send_otp_email


# ------------------------------------------------------------------ #
# LANDING
# ------------------------------------------------------------------ #
def landing(request):
    if not request.is_main_domain:
        return redirect('dashboard')
    return render(request, 'landing/index.html')


# ------------------------------------------------------------------ #
# REGISTER — Step 1: Collect form data, send OTP
# ------------------------------------------------------------------ #
def register(request):
    if not request.is_main_domain:
        return redirect('dashboard')

    if request.method == 'POST':
        org_name  = request.POST.get('org_name', '').strip()
        sector    = request.POST.get('sector', 'other')
        email     = request.POST.get('email', '').strip().lower()
        name      = request.POST.get('name', '').strip()
        password  = request.POST.get('password', '')
        password2 = request.POST.get('password2', '')
        city      = request.POST.get('city', '').strip()
        phone     = request.POST.get('phone', '').strip()

        # Validations
        if not all([org_name, email, name, password]):
            messages.error(request, 'All required fields must be filled.')
            return render(request, 'accounts/register.html', {
                'sectors': SECTOR_CHOICES, 'post': request.POST
            })

        if password != password2:
            messages.error(request, 'Passwords do not match.')
            return render(request, 'accounts/register.html', {
                'sectors': SECTOR_CHOICES, 'post': request.POST
            })

        if len(password) < 8:
            messages.error(request, 'Password must be at least 8 characters.')
            return render(request, 'accounts/register.html', {
                'sectors': SECTOR_CHOICES, 'post': request.POST
            })

        if User.objects.filter(email=email).exists():
            messages.error(request, 'This email is already registered.')
            return render(request, 'accounts/register.html', {
                'sectors': SECTOR_CHOICES, 'post': request.POST
            })

        # Store form data in OTPVerification, send OTP
        form_data = {
            'org_name': org_name,
            'sector':   sector,
            'email':    email,
            'name':     name,
            'password': password,
            'city':     city,
            'phone':    phone,
        }

        otp_obj  = OTPVerification.create_for_email(email, form_data)
        email_ok = send_otp_email(email, otp_obj.otp, org_name)

        if not email_ok:
            messages.error(request, 'Failed to send OTP email. Please check the email address and try again.')
            return render(request, 'accounts/register.html', {
                'sectors': SECTOR_CHOICES, 'post': request.POST
            })

        # Store email in session to use on OTP page
        request.session['otp_email'] = email

        return redirect('verify_otp')

    return render(request, 'accounts/register.html', {
        'sectors':    SECTOR_CHOICES,
        'trial_days': TRIAL_DAYS,
    })


# ------------------------------------------------------------------ #
# VERIFY OTP — Step 2: Validate OTP, create account
# ------------------------------------------------------------------ #
def verify_otp(request):
    if not request.is_main_domain:
        return redirect('dashboard')

    email = request.session.get('otp_email', '')
    if not email:
        messages.error(request, 'Session expired. Please register again.')
        return redirect('register')

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

        # Resend OTP
        if action == 'resend':
            otp_obj = OTPVerification.objects.filter(
                email=email, is_used=False
            ).order_by('-created_at').first()

            if otp_obj:
                form_data = otp_obj.form_data
                new_otp   = OTPVerification.create_for_email(email, form_data)
                send_otp_email(email, new_otp.otp, form_data.get('org_name', ''))
                messages.success(request, 'A new OTP has been sent to your email.')
            else:
                messages.error(request, 'Session expired. Please register again.')
                return redirect('register')

            return render(request, 'accounts/verify_otp.html', {
                'email': email,
            })

        # Verify OTP
        entered_otp = request.POST.get('otp', '').strip()

        otp_obj = OTPVerification.objects.filter(
            email   = email,
            is_used = False,
        ).order_by('-created_at').first()

        if not otp_obj:
            messages.error(request, 'OTP not found. Please register again.')
            return redirect('register')

        if otp_obj.is_expired():
            messages.error(request, 'OTP has expired. Please request a new one.')
            return render(request, 'accounts/verify_otp.html', {'email': email})

        if otp_obj.otp != entered_otp:
            messages.error(request, 'Incorrect OTP. Please try again.')
            return render(request, 'accounts/verify_otp.html', {'email': email})

        # OTP is valid — create account
        otp_obj.is_used = True
        otp_obj.save()

        form_data = otp_obj.form_data
        org_name  = form_data.get('org_name', '')
        sector    = form_data.get('sector', 'other')
        name      = form_data.get('name', '')
        password  = form_data.get('password', '')
        city      = form_data.get('city', '')
        phone     = form_data.get('phone', '')

        # Check if org/user already exists (handle duplicate OTP submissions)
        if Organization.objects.filter(email=email).exists():
            Organization.objects.filter(email=email).delete()
        if User.objects.filter(email=email).exists():
            User.objects.filter(email=email).delete()

        # Generate unique slug
        base_slug = slugify(org_name)
        slug      = base_slug
        counter   = 1
        while Organization.objects.filter(slug=slug).exists():
            slug = f"{base_slug}-{counter}"
            counter += 1

        # Create Organization
        org = Organization.objects.create(
            name   = org_name,
            slug   = slug,
            sector = sector,
            email  = email,
            phone  = phone,
            city   = city,
        )

        # UIDAI setup is now automatic — Avighna is the single registered
        # OVSE, so every client is instantly ready to verify. No AC/SA
        # code or RSA keys need to be collected from the client anymore.
        org.uidai_setup_done = True
        org.save(update_fields=['uidai_setup_done'])

        # Start 15-day free trial
        org.start_trial()

        # Create trial subscription record
        Subscription.objects.create(
            org        = org,
            plan       = 'trial',
            status     = 'trial',
            amount     = 0,
            start_date = org.trial_start,
            end_date   = org.trial_end,
            notes      = f'{TRIAL_DAYS}-day free trial started on registration.',
        )

        # Create admin user
        user = User.objects.create_user(
            email    = email,
            password = password,
            name     = name,
            org      = org,
            role     = 'org_admin',
        )

        # Clear session
        request.session.pop('otp_email', None)

        login(request, user)
        messages.success(request, f'Welcome {name}! Your {TRIAL_DAYS}-day free trial has started.')
        return redirect('dashboard')

    return render(request, 'accounts/verify_otp.html', {
        'email': email,
    })


# ------------------------------------------------------------------ #
# LOGIN / LOGOUT
# ------------------------------------------------------------------ #
def login_view(request):
    if request.method == 'POST':
        email    = request.POST.get('email', '').strip().lower()
        password = request.POST.get('password', '')
        user     = authenticate(request, email=email, password=password)
        if user:
            login(request, user)
            if user.is_super_admin:
                return redirect('super_admin_dashboard')
            return redirect('dashboard')
        messages.error(request, 'Invalid email or password.')
    return render(request, 'accounts/login.html')


def logout_view(request):
    logout(request)
    return redirect('login')


# ------------------------------------------------------------------ #
# UIDAI SETUP — removed. Avighna is the single OVSE and verification
# fields are now a fixed platform standard, so there's nothing for a
# client to configure here anymore. Kept as a redirect for old links.
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def setup_uidai(request):
    return redirect('dashboard')


# ------------------------------------------------------------------ #
# VERIFICATION FIELDS — removed. Every client now gets the same fixed
# standard set (Photo, Name, DOB, Gender, Address, Mobile). Kept as a
# redirect for old links/bookmarks.
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def verification_fields_setup(request):
    return redirect('dashboard')


# ------------------------------------------------------------------ #
# TRIAL EXPIRED
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def trial_expired(request):
    org = request.user.org
    return render(request, 'accounts/trial_expired.html', {
        'org':       org,
        'plans':     PLAN_LIMITS,
    })


# ------------------------------------------------------------------ #
# UPGRADE PLAN
# ------------------------------------------------------------------ #
@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'):
            messages.error(request, 'Invalid plan selected.')
            return render(request, 'accounts/upgrade.html', {
                'org': org, 'plans': PLAN_LIMITS
            })

        # Activate the plan
        org.activate_plan(selected_plan)

        # Create subscription record
        Subscription.objects.create(
            org        = org,
            plan       = selected_plan,
            status     = 'active',
            amount     = PLAN_LIMITS[selected_plan]['price'],
            start_date = org.plan_start,
            end_date   = org.plan_end,
            notes      = f'Upgraded to {selected_plan} plan.',
        )

        messages.success(
            request,
            f'Plan upgraded to {selected_plan.title()} successfully. '
            f'You can now verify visitors again.'
        )
        return redirect('dashboard')

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


# ------------------------------------------------------------------ #
# CLIENT DASHBOARD
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def dashboard(request):
    user = request.user

    if user.is_super_admin:
        return redirect('super_admin_dashboard')

    org = user.org
    if not org:
        messages.error(request, 'No organization found for your account.')
        return redirect('login')

    from_date = request.GET.get('from_date', '')
    to_date   = request.GET.get('to_date', '')

    from verification.models import Visitor
    from django.db.models import Count
    from django.db.models.functions import TruncDate
    import json

    visitors = Visitor.objects.filter(org=org).order_by('-created_at')
    if from_date:
        visitors = visitors.filter(created_at__date__gte=from_date)
    if to_date:
        visitors = visitors.filter(created_at__date__lte=to_date)

    total_visitors = Visitor.objects.filter(org=org).count()
    today_visitors = Visitor.objects.filter(
        org=org, created_at__date=now().date()
    ).count()

    chart_data = (
        Visitor.objects.filter(org=org)
        .annotate(date=TruncDate('created_at'))
        .values('date')
        .annotate(count=Count('id'))
        .order_by('date')
    )
    dates  = [str(item['date'])  for item in chart_data]
    counts = [item['count'] for item in chart_data]

    # Library/Coaching module stats
    from students.models import Student, Attendance, FeePayment
    present_today = Attendance.objects.filter(
        org=org, date=Attendance.attendance_date_for(now()), event='IN'
    ).values('student').distinct().count()
    total_students = Student.objects.filter(org=org, is_active=True).count()
    current_month  = now().strftime('%Y-%m')
    fees_collected = FeePayment.objects.filter(org=org, month=current_month).values_list('amount', flat=True)
    fees_collected_total = sum(fees_collected) if fees_collected else 0

    return render(request, 'dashboard/index.html', {
        'org':            org,
        'visitors':       visitors[:50],
        'total_visitors': total_visitors,
        'today_visitors': today_visitors,
        'dates':          json.dumps(dates),
        'counts':         json.dumps(counts),
        'from_date':      from_date,
        'to_date':        to_date,
        'remaining':      org.verifications_remaining(),
        'can_export':     org.can_export(),
        'trial_days_left': org.trial_days_remaining(),
        'present_today':   present_today,
        'total_students':  total_students,
        'fees_collected_total': fees_collected_total,
    })


# ------------------------------------------------------------------ #
# PROFILE
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def profile(request):
    org = request.user.org
    if not org:
        return redirect('landing')

    if request.method == 'POST':
        org.name    = request.POST.get('org_name', org.name).strip()
        org.phone   = request.POST.get('phone', org.phone).strip()
        org.city    = request.POST.get('city', org.city).strip()
        org.address = request.POST.get('address', org.address).strip()

        fee_raw = request.POST.get('default_monthly_fee', '').strip()
        if fee_raw.isdigit():
            org.default_monthly_fee = int(fee_raw)

        org.save()
        messages.success(request, 'Profile updated successfully.')
        return redirect('profile')

    subscriptions = Subscription.objects.filter(org=org).order_by('-created_at')[:5]

    return render(request, 'accounts/profile.html', {
        'org':           org,
        'subscriptions': subscriptions,
    })


# ------------------------------------------------------------------ #
# SUPER ADMIN DASHBOARD
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def super_admin_dashboard(request):
    if not request.user.is_super_admin:
        return redirect('dashboard')

    orgs         = Organization.objects.all().order_by('-created_at')
    total_orgs   = orgs.count()
    active_orgs  = orgs.filter(is_active=True).count()
    trial_orgs   = orgs.filter(is_trial=True, trial_expired=False).count()
    expired_orgs = orgs.filter(trial_expired=True).count()
    paid_orgs    = orgs.filter(is_trial=False, is_active=True).count()

    from verification.models import Visitor
    total_verifs = Visitor.objects.count()

    return render(request, 'superadmin/dashboard.html', {
        'orgs':         orgs[:30],
        'total_orgs':   total_orgs,
        'active_orgs':  active_orgs,
        'trial_orgs':   trial_orgs,
        'expired_orgs': expired_orgs,
        'paid_orgs':    paid_orgs,
        'total_verifs': total_verifs,
    })


# ------------------------------------------------------------------ #
# SUPER ADMIN — ACTIVATE / DEACTIVATE CLIENT
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def toggle_org(request, slug):
    if not request.user.is_super_admin:
        return redirect('dashboard')

    try:
        org = Organization.objects.get(slug=slug)
        org.is_active = not org.is_active
        org.save(update_fields=['is_active'])
        status = 'activated' if org.is_active else 'deactivated'
        messages.success(request, f'{org.name} has been {status}.')
    except Organization.DoesNotExist:
        messages.error(request, 'Organization not found.')

    return redirect('super_admin_dashboard')


# ------------------------------------------------------------------ #
# SUPER ADMIN — MANUALLY EXTEND TRIAL
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def extend_trial(request, slug):
    if not request.user.is_super_admin:
        return redirect('dashboard')

    try:
        org           = Organization.objects.get(slug=slug)
        org.trial_end = org.trial_end + timedelta(days=15) if org.trial_end else now() + timedelta(days=15)
        org.trial_expired = False
        org.is_active     = True
        org.save(update_fields=['trial_end', 'trial_expired', 'is_active'])
        messages.success(request, f'Trial extended by 15 days for {org.name}.')
    except Organization.DoesNotExist:
        messages.error(request, 'Organization not found.')

    return redirect('super_admin_dashboard')


# ------------------------------------------------------------------ #
# SUPER ADMIN — MANUALLY ACTIVATE A PAID PLAN (no payment gateway)
# Temporary tool for while Cashfree/coupon flow is still being set up —
# superadmin marks an org as paid directly.
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def manual_activate_plan(request, slug):
    if not request.user.is_super_admin:
        return redirect('dashboard')

    if request.method != 'POST':
        return redirect('super_admin_dashboard')

    plan = request.POST.get('plan', '')
    if plan not in ('starter', 'business', 'enterprise'):
        messages.error(request, 'Invalid plan selected.')
        return redirect('super_admin_dashboard')

    try:
        org = Organization.objects.get(slug=slug)
    except Organization.DoesNotExist:
        messages.error(request, 'Organization not found.')
        return redirect('super_admin_dashboard')

    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'Manually activated by superadmin ({request.user.email}).',
    )
    Payment.objects.create(
        org             = org,
        plan            = plan,
        original_amount = 0,
        discount_amount = 0,
        gst_amount      = 0,
        final_amount    = 0,
        gateway         = 'manual_admin',
        status          = 'success',
        notes           = f'Manually activated by superadmin ({request.user.email}). No payment collected.',
    )

    messages.success(request, f'{plan.title()} plan manually activated for {org.name}.')
    return redirect('super_admin_dashboard')


# ------------------------------------------------------------------ #
# SUPER ADMIN — PLATFORM (OVSE) SETTINGS
# ------------------------------------------------------------------ #
@login_required(login_url='/login/')
def platform_settings(request):
    if not request.user.is_super_admin:
        return redirect('dashboard')

    settings_obj = PlatformSettings.get_solo()

    if request.method == 'POST':
        ovse_base_url = request.POST.get('ovse_base_url', '').strip().rstrip('/')
        ac_code       = request.POST.get('ac_code', '').strip()
        sa_code       = request.POST.get('sa_code', '').strip()
        private_key   = request.POST.get('private_key', '').strip()
        public_key    = request.POST.get('public_key', '').strip()
        payment_gateway_enabled = request.POST.get('payment_gateway_enabled') == 'on'
        support_email = request.POST.get('support_email', '').strip()

        validator = URLValidator(schemes=['https'])
        try:
            validator(ovse_base_url)
        except ValidationError:
            messages.error(request, 'Please enter a valid https:// OVSE base URL.')
            return render(request, 'superadmin/platform_settings.html', {
                'settings_obj': settings_obj,
                'orgs':         Organization.objects.all().order_by('name'),
            })

        settings_obj.ovse_base_url = ovse_base_url
        settings_obj.ac_code       = ac_code
        settings_obj.sa_code       = sa_code
        settings_obj.private_key   = private_key
        settings_obj.public_key    = public_key
        settings_obj.payment_gateway_enabled = payment_gateway_enabled
        settings_obj.support_email = support_email or settings_obj.support_email
        settings_obj.save()

        # Every org's callback URL is derived from this base, so regenerate
        # them all now — otherwise existing orgs would keep their old URL.
        regenerated = 0
        for org in Organization.objects.all():
            new_url = org.build_callback_url()
            if org.callback_url != new_url:
                org.callback_url = new_url
                org.save(update_fields=['callback_url'])
                regenerated += 1

        messages.success(
            request,
            f'Platform UIDAI settings saved. {regenerated} organization callback URL(s) regenerated.'
        )
        return redirect('platform_settings')

    return render(request, 'superadmin/platform_settings.html', {
        'settings_obj': settings_obj,
        'orgs':         Organization.objects.all().order_by('name'),
    })


# ------------------------------------------------------------------ #
# AJAX — CHECK SLUG AVAILABILITY
# ------------------------------------------------------------------ #
def check_slug(request):
    from django.conf import settings
    slug   = slugify(request.GET.get('name', ''))
    exists = Organization.objects.filter(slug=slug).exists()
    return JsonResponse({
        'slug':      slug,
        'available': not exists,
        'subdomain': f"{slug}.{settings.MAIN_DOMAIN}",
    })