# companies/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponseForbidden

from .models import Company, CompanySettings, Plan, SuperAdmin2FA


def company_inactive(request):
    """Shown when a company's subscription has expired or is suspended."""
    company = getattr(request, 'company', None)
    return render(request, 'companies/inactive.html', {'company': company})


# ─────────────────────────────────────────────────────────────
# SUPERADMIN — company management views
# ─────────────────────────────────────────────────────────────

def superadmin_required(view_func):
    """Decorator: only Django superusers can access.
    Also enforces 2FA if enabled for the superuser — redirects to verify page
    until the second factor is confirmed for this session.
    """
    from functools import wraps
    @wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if not request.user.is_authenticated or not request.user.is_superuser:
            return HttpResponseForbidden('Superadmin access only.')
        # If 2FA is pending for this session, bounce to verify page
        if request.session.get('superadmin_2fa_pending'):
            return redirect('superadmin_2fa_verify')
        return view_func(request, *args, **kwargs)
    return wrapper


@superadmin_required
def company_list(request):
    """Superadmin: list all companies + platform-wide revenue overview."""
    from sales.models import POSOrder
    from subscriptions.models import PaymentTransaction as SubPaymentTransaction
    from django.db.models import Sum, Count
    from django.db.models.functions import TruncDate, TruncMonth
    from django.utils import timezone
    from decimal import Decimal
    from datetime import timedelta

    companies = Company.objects.select_related('plan').order_by('name')

    today = timezone.now().date()
    this_month_start = today.replace(day=1)
    last_month_end   = this_month_start - timedelta(days=1)
    last_month_start = last_month_end.replace(day=1)
    twelve_months_ago = today.replace(day=1) - timedelta(days=365)

    # ── Platform-wide POS totals ──────────────────────────────────────────
    completed_orders = POSOrder.objects.filter(status='completed')
    platform_total_revenue = completed_orders.aggregate(t=Sum('final_amount'))['t'] or Decimal('0')
    platform_today_revenue = completed_orders.filter(created_at__date=today).aggregate(t=Sum('final_amount'))['t'] or Decimal('0')
    platform_total_orders  = completed_orders.count()
    platform_today_orders  = completed_orders.filter(created_at__date=today).count()
    active_companies = companies.filter(is_active=True).count()

    # ── Daily POS revenue last 30 days ────────────────────────────────────
    thirty_days_ago = today - timedelta(days=29)
    daily_revenue = (
        completed_orders
        .filter(created_at__date__gte=thirty_days_ago)
        .annotate(day=TruncDate('created_at'))
        .values('day')
        .annotate(total=Sum('final_amount'), orders=Count('id'))
        .order_by('day')
    )

    # ── Per-company POS revenue (top 15) ─────────────────────────────────
    company_revenues = (
        completed_orders
        .values('company__name', 'company__slug')
        .annotate(total=Sum('final_amount'), orders=Count('id'))
        .order_by('-total')[:15]
    )

    # ── SwiftPOS Subscription Revenue (paid transactions only) ───────────
    paid_subs = SubPaymentTransaction.objects.filter(status='paid')

    sub_total_revenue   = paid_subs.aggregate(t=Sum('final_amount'))['t'] or Decimal('0')
    sub_this_month      = paid_subs.filter(paid_at__date__gte=this_month_start).aggregate(t=Sum('final_amount'))['t'] or Decimal('0')
    sub_last_month      = paid_subs.filter(paid_at__date__gte=last_month_start, paid_at__date__lte=last_month_end).aggregate(t=Sum('final_amount'))['t'] or Decimal('0')
    sub_total_count     = paid_subs.count()
    sub_this_month_count = paid_subs.filter(paid_at__date__gte=this_month_start).count()

    # MoM growth %
    if sub_last_month > 0:
        sub_mom_growth = round(float((sub_this_month - sub_last_month) / sub_last_month * 100), 1)
    else:
        sub_mom_growth = None

    # 12-month trend
    sub_monthly_trend = (
        paid_subs
        .filter(paid_at__date__gte=twelve_months_ago)
        .annotate(month=TruncMonth('paid_at'))
        .values('month')
        .annotate(total=Sum('final_amount'), count=Count('id'))
        .order_by('month')
    )

    # Revenue per plan
    sub_by_plan = (
        paid_subs
        .values('plan__name')
        .annotate(total=Sum('final_amount'), count=Count('id'))
        .order_by('-total')
    )

    # Top paying companies (subscription)
    sub_top_companies = (
        paid_subs
        .values('company__name', 'company__slug')
        .annotate(total=Sum('final_amount'), count=Count('id'))
        .order_by('-total')[:8]
    )

    return render(request, 'companies/superadmin/list.html', {
        'companies': companies,
        'platform_total_revenue': platform_total_revenue,
        'platform_today_revenue': platform_today_revenue,
        'platform_total_orders':  platform_total_orders,
        'platform_today_orders':  platform_today_orders,
        'active_companies': active_companies,
        'daily_revenue': list(daily_revenue),
        'company_revenues': list(company_revenues),
        'today': today,
        # Subscription revenue
        'sub_total_revenue':    sub_total_revenue,
        'sub_this_month':       sub_this_month,
        'sub_last_month':       sub_last_month,
        'sub_total_count':      sub_total_count,
        'sub_this_month_count': sub_this_month_count,
        'sub_mom_growth':       sub_mom_growth,
        'sub_monthly_trend':    list(sub_monthly_trend),
        'sub_by_plan':          list(sub_by_plan),
        'sub_top_companies':    list(sub_top_companies),
    })


@superadmin_required
def company_detail(request, slug):
    """Superadmin: view/edit a specific company."""
    from sales.models import POSOrder
    from django.db.models import Sum
    from django.utils import timezone

    company = get_object_or_404(Company, slug=slug)
    cs = getattr(company, 'settings', None)
    
    today = timezone.now().date()
    
    # Calculate stats
    today_sales = POSOrder.objects.filter(company=company, created_at__date=today, status='completed').aggregate(total=Sum('final_amount'))['total'] or 0
    total_revenue = POSOrder.objects.filter(company=company, status='completed').aggregate(total=Sum('final_amount'))['total'] or 0
    today_orders = POSOrder.objects.filter(company=company, created_at__date=today, status='completed').count()
    total_orders_count = POSOrder.objects.filter(company=company, status='completed').count()

    return render(request, 'companies/superadmin/detail.html', {
        'company': company,
        'cs': cs,
        'plans': Plan.objects.filter(is_active=True),
        'today_sales': today_sales,
        'total_revenue': total_revenue,
        'today_orders': today_orders,
        'total_orders_count': total_orders_count,
    })


@superadmin_required
def company_toggle(request, slug):
    """Superadmin: activate/deactivate a company."""
    company = get_object_or_404(Company, slug=slug)
    company.is_active = not company.is_active
    company.save()
    status = "activated" if company.is_active else "suspended"
    messages.success(request, f"Company '{company.name}' has been {status}.")
    return redirect('superadmin_company_list')


@superadmin_required
def company_create(request):
    """Superadmin: create a new company + admin account + branch."""
    plans = Plan.objects.filter(is_active=True)
    if request.method == 'POST':
        from django.utils.text import slugify
        from django.db import transaction
        from accounts.models import CustomUser
        from core.models import Branch

        name = request.POST.get('name', '').strip()
        email = request.POST.get('email', '').strip()
        phone = request.POST.get('phone', '').strip()
        plan_id = request.POST.get('plan')
        expiry_date = request.POST.get('expiry_date')
        
        # Admin user details
        admin_username = request.POST.get('admin_username', '').strip()
        admin_email = request.POST.get('admin_email', '').strip()
        admin_password = request.POST.get('admin_password', '').strip()

        slug = slugify(name)
        if not slug:
            messages.error(request, "Name cannot be empty.")
            return render(request, 'companies/superadmin/create.html', {'plans': plans})

        if Company.objects.filter(slug=slug).exists():
            messages.error(request, f"A company with slug '{slug}' already exists.")
            return render(request, 'companies/superadmin/create.html', {'plans': plans})

        if CustomUser.objects.filter(username=admin_username).exists():
            messages.error(request, f"Username '{admin_username}' is already taken.")
            return render(request, 'companies/superadmin/create.html', {'plans': plans})

        try:
            with transaction.atomic():
                plan = get_object_or_404(Plan, id=plan_id) if plan_id else None
                company = Company.objects.create(
                    name=name, slug=slug, email=email, phone=phone, plan=plan, 
                    is_active=True, expiry_date=expiry_date if expiry_date else None
                )
                CompanySettings.objects.create(company=company, business_name=name)
                
                # Create default branch
                branch = Branch.objects.create(
                    company=company,
                    name="Main Branch",
                    code="MAIN"
                )
                
                # Create admin user
                user = CustomUser.objects.create_user(
                    username=admin_username,
                    email=admin_email,
                    password=admin_password,
                    role='admin',
                    company=company,
                    branch=branch
                )
                
            messages.success(request, f"Company '{name}' and admin user '{admin_username}' created successfully!")
            return redirect('superadmin_company_list')
        except Exception as e:
            messages.error(request, f"Error creating company: {str(e)}")
            return render(request, 'companies/superadmin/create.html', {'plans': plans})

    return render(request, 'companies/superadmin/create.html', {'plans': plans})


@superadmin_required
def company_update_subscription(request, slug):
    """Superadmin: update company plan and expiry date."""
    from subscriptions.models import Subscription, PaymentTransaction
    from django.utils import timezone
    from decimal import Decimal

    company = get_object_or_404(Company, slug=slug)
    if request.method == 'POST':
        plan_id = request.POST.get('plan')
        expiry_date = request.POST.get('expiry_date')
        
        company.plan_id = plan_id if plan_id else None
        company.expiry_date = expiry_date if expiry_date else None
        company.save()
        
        if plan_id:
            # 1. Deactivate all existing active subscriptions
            Subscription.objects.filter(company=company, is_active=True).update(is_active=False)
            
            # 2. Create the new active subscription
            plan = get_object_or_404(Plan, id=plan_id)
            sub = Subscription.objects.create(
                company=company,
                plan=plan,
                billing_cycle='monthly',
                start_date=timezone.now().date(),
                expiry_date=expiry_date if expiry_date else None,
                is_trial=False,
                is_active=True,
                payment_status='paid'
            )
            
            # 3. Create a manual transaction record for billing history
            #    Use the plan's actual price so revenue reports are accurate
            plan_price = Decimal(str(getattr(plan, 'price', '0') or '0'))
            PaymentTransaction.objects.create(
                company=company,
                subscription=sub,
                plan=plan,
                billing_cycle='monthly',
                amount=plan_price,
                discount_amount=Decimal('0.00'),
                final_amount=plan_price,
                status='paid',
                gateway='free',
                payment_method='Manual Override by Admin',
                paid_at=timezone.now()
            )
        
        messages.success(request, f"Subscription for '{company.name}' updated seamlessly.")
        return redirect('superadmin_company_detail', slug=slug)
    return redirect('superadmin_company_detail', slug=slug)


@superadmin_required
def server_setup(request):
    """Superadmin: Integrations & Automation setup guide (webhooks + cPanel cron)."""
    import sys, os
    python_path = sys.executable
    manage_py   = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'manage.py')
    cpanel_cron_command   = f'{python_path} {manage_py} process_subscriptions'
    insights_cron_command = f'{python_path} {manage_py} generate_insights'

    # Build webhook URLs from request
    monnify_webhook_url  = request.build_absolute_uri('/webhooks/monnify/')
    paystack_webhook_url = request.build_absolute_uri('/subscription/webhooks/paystack/')

    return render(request, 'companies/superadmin/server_setup.html', {
        'webhook_url': monnify_webhook_url,           # kept for backward compat
        'monnify_webhook_url': monnify_webhook_url,
        'paystack_webhook_url': paystack_webhook_url,
        'cpanel_cron_command': cpanel_cron_command,
        'insights_cron_command': insights_cron_command,
    })


# ─────────────────────────────────────────────────────────────
# SUPERADMIN 2FA — verification views
# ─────────────────────────────────────────────────────────────

def _sa_2fa_send_email_otp(request, user):
    """Generate OTP, store in session, send email."""
    import random, time
    from core.email_utils import send_2fa_otp_email

    otp = f"{random.randint(100000, 999999)}"
    request.session['sa_2fa_otp']      = otp
    request.session['sa_2fa_expires']  = time.time() + 600   # 10 min
    request.session['sa_2fa_attempts'] = 0
    send_2fa_otp_email(
        user_email=user.email,
        otp_code=otp,
        company_name='SwiftPOS Superadmin',
        username=user.get_full_name() or user.username,
    )


def superadmin_2fa_verify(request):
    """
    Second-factor verification for superusers.
    Supports both email OTP and TOTP (Google Authenticator).
    Only reachable when session['superadmin_2fa_pending'] is True.
    """
    import time

    # Must be logged in as superuser and have a pending 2FA flag
    if not request.user.is_authenticated or not request.user.is_superuser:
        return redirect('login')
    if not request.session.get('superadmin_2fa_pending'):
        return redirect('superadmin_company_list')

    try:
        cfg = SuperAdmin2FA.objects.get(user=request.user, is_enabled=True)
    except SuperAdmin2FA.DoesNotExist:
        # Config deleted while logged in — grant access
        request.session.pop('superadmin_2fa_pending', None)
        return redirect('superadmin_company_list')

    method = cfg.method

    if request.method == 'POST':
        code = request.POST.get('code', '').strip().replace(' ', '')

        if method == SuperAdmin2FA.METHOD_EMAIL:
            # ── Email OTP check ───────────────────────────────────────────
            attempts = request.session.get('sa_2fa_attempts', 0)
            expires  = request.session.get('sa_2fa_expires', 0)
            stored   = request.session.get('sa_2fa_otp', '')

            if time.time() > expires:
                messages.error(request, 'Your OTP has expired. Please request a new one.')
                return redirect('superadmin_2fa_resend')

            if attempts >= 5:
                messages.error(request, 'Too many incorrect attempts. Please log in again.')
                from django.contrib.auth import logout
                logout(request)
                return redirect('login')

            if code == stored:
                request.session.pop('superadmin_2fa_pending', None)
                request.session.pop('sa_2fa_otp', None)
                request.session.pop('sa_2fa_expires', None)
                request.session.pop('sa_2fa_attempts', None)
                messages.success(request, 'Two-factor authentication verified. Welcome!')
                return redirect('superadmin_company_list')
            else:
                request.session['sa_2fa_attempts'] = attempts + 1
                remaining = 5 - (attempts + 1)
                messages.error(request, f'Incorrect code. {remaining} attempt(s) remaining.')

        elif method == SuperAdmin2FA.METHOD_TOTP:
            # ── TOTP check ────────────────────────────────────────────────
            if cfg.verify_totp(code):
                request.session.pop('superadmin_2fa_pending', None)
                messages.success(request, 'Two-factor authentication verified. Welcome!')
                return redirect('superadmin_company_list')
            else:
                messages.error(request, 'Invalid authenticator code. Please try again.')

    return render(request, 'companies/superadmin/2fa_verify.html', {
        'method': method,
        'is_email': method == SuperAdmin2FA.METHOD_EMAIL,
        'is_totp':  method == SuperAdmin2FA.METHOD_TOTP,
        'masked_email': _mask_email(request.user.email) if request.user.email else '',
    })


def superadmin_2fa_resend(request):
    """Resend email OTP for superadmin (email method only)."""
    if not request.user.is_authenticated or not request.user.is_superuser:
        return redirect('login')
    if not request.session.get('superadmin_2fa_pending'):
        return redirect('superadmin_company_list')

    try:
        cfg = SuperAdmin2FA.objects.get(user=request.user, is_enabled=True, method=SuperAdmin2FA.METHOD_EMAIL)
    except SuperAdmin2FA.DoesNotExist:
        return redirect('superadmin_2fa_verify')

    _sa_2fa_send_email_otp(request, request.user)
    messages.success(request, 'A new OTP has been sent to your email.')
    return redirect('superadmin_2fa_verify')


def _mask_email(email):
    if not email or '@' not in email:
        return email
    local, domain = email.split('@', 1)
    return local[:2] + '***@' + domain
