from django.shortcuts import render, redirect
import json
import logging
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden
from django.contrib import messages
from django.db import models
from django.db.models import Count, Sum
from django.views.decorators.http import require_POST
from django.contrib.auth import get_user_model
from django.db import transaction
from django.urls import reverse

from core.models import SystemSettings
from plans.models import Plan
from domains.models import Domain
from billing.models import Invoice
from .forms import SystemSettingsForm, PlanForm, DomainPlanSwitchForm, DomainGrantTrafficForm, InvoiceAdjustmentForm
from billing.models import Invoice, InvoiceItem
from decimal import Decimal
from django.utils import timezone
from core.goedge_client import GoEdgeClient
from core.models import OperationLog


def _staff_only(request):
    if not request.user.is_authenticated:
        return False
    return request.user.is_staff


@login_required
def dashboard(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    users_count = request.user.__class__.objects.count()
    domains_count = Domain.objects.count()
    plans_count = Plan.objects.count()
    unpaid_invoices = Invoice.objects.filter(status='unpaid').count() if hasattr(Invoice, 'status') else 0
    return render(request, 'admin_panel/dashboard.html', {
        'users_count': users_count,
        'domains_count': domains_count,
        'plans_count': plans_count,
        'unpaid_invoices': unpaid_invoices,
    })


@login_required
def operation_logs(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    q_actor = request.GET.get('actor', '').strip()
    q_action = request.GET.get('action', '').strip()
    q_target = request.GET.get('target', '').strip()
    start = request.GET.get('start') or ''
    end = request.GET.get('end') or ''
    export = request.GET.get('export') or ''
    qs = OperationLog.objects.select_related('actor').all()
    if q_actor:
        qs = qs.filter(actor__username__icontains=q_actor)
    if q_action:
        qs = qs.filter(action__icontains=q_action)
    if q_target:
        qs = qs.filter(target__icontains=q_target)
    if start:
        try:
            from django.utils.dateparse import parse_datetime, parse_date
            dt = parse_datetime(start) or parse_date(start)
            if dt:
                qs = qs.filter(created_at__gte=dt)
        except Exception:
            pass
    if end:
        try:
            from django.utils.dateparse import parse_datetime, parse_date
            dt = parse_datetime(end) or parse_date(end)
            if dt:
                qs = qs.filter(created_at__lte=dt)
        except Exception:
            pass
    qs = qs.order_by('-created_at')
    if export == 'csv':
        import csv
        from django.http import HttpResponse
        resp = HttpResponse(content_type='text/csv; charset=utf-8')
        resp['Content-Disposition'] = 'attachment; filename="operation_logs.csv"'
        writer = csv.writer(resp)
        writer.writerow(['时间', '操作人', '动作', '目标', '详情'])
        for row in qs[:5000]:
            writer.writerow([
                row.created_at, (row.actor.username if row.actor else ''), row.action, row.target, row.detail,
            ])
        return resp
    from django.core.paginator import Paginator
    paginator = Paginator(qs, 50)
    page = request.GET.get('page') or 1
    try:
        page_obj = paginator.get_page(page)
    except Exception:
        page_obj = paginator.get_page(1)
    return render(request, 'admin_panel/operation_logs.html', {
        'page_obj': page_obj,
        'actor': q_actor,
        'action': q_action,
        'target': q_target,
        'start': start,
        'end': end,
    })


@login_required
def settings(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')

    settings_obj = SystemSettings.objects.order_by('id').first()
    if not settings_obj:
        settings_obj = SystemSettings.objects.create()

    if request.method == 'POST':
        action = request.POST.get('action') or 'save'
        if action == 'save':
            form = SystemSettingsForm(request.POST, instance=settings_obj)
            if form.is_valid():
                form.save()
                messages.success(request, '系统设置已保存')
                return redirect('admin_panel:settings')
            else:
                messages.error(request, '保存失败，请检查表单字段')
        elif action == 'get_token':
            form = SystemSettingsForm(instance=settings_obj)
            try:
                client = GoEdgeClient()
                token = client._ensure_token()  # 触发获取/续期
                messages.success(request, f'已获取 AccessToken（已缓存）：{token[:8]}...')
            except Exception as e:
                messages.error(request, f'获取 AccessToken 失败：{e}')
        elif action == 'test_connection':
            form = SystemSettingsForm(instance=settings_obj)
            try:
                client = GoEdgeClient()  # 构造时即验证 base_url
                _ = client._headers()  # 触发令牌确保
                messages.success(request, '与 GoEdge API 连接正常（令牌有效）')
            except Exception as e:
                messages.error(request, f'连接测试失败：{e}')
        elif action == 'validate_access_log_policy':
            form = SystemSettingsForm(request.POST, instance=settings_obj)
            if form.is_valid():
                pid = form.cleaned_data.get('default_http_access_log_policy_id')
                if not pid:
                    messages.error(request, '请先填写访问日志策略ID')
                else:
                    try:
                        client = GoEdgeClient()
                        exists = client.check_access_log_policy_exists(int(pid))
                        messages.success(request, f'访问日志策略ID {pid} 校验结果：{"存在" if exists else "不存在"}')
                        # 操作日志
                        try:
                            OperationLog.objects.create(
                                actor=request.user,
                                action='validate_policy_id',
                                target='SystemSettings',
                                detail=json.dumps({'type': 'access_log', 'policyId': int(pid), 'exists': bool(exists)}, ensure_ascii=False)
                            )
                        except Exception:
                            logger.exception('operation log write failed')
                    except Exception as e:
                        messages.error(request, f'访问日志策略校验失败：{e}')
            else:
                messages.error(request, '策略ID格式不正确，请检查输入')
        elif action == 'validate_firewall_policy':
            form = SystemSettingsForm(request.POST, instance=settings_obj)
            if form.is_valid():
                pid = form.cleaned_data.get('default_http_firewall_policy_id')
                if not pid:
                    messages.error(request, '请先填写WAF策略ID')
                else:
                    try:
                        client = GoEdgeClient()
                        exists = client.check_firewall_policy_exists(int(pid))
                        messages.success(request, f'WAF策略ID {pid} 校验结果：{"存在" if exists else "不存在"}')
                        # 操作日志
                        try:
                            OperationLog.objects.create(
                                actor=request.user,
                                action='validate_policy_id',
                                target='SystemSettings',
                                detail=json.dumps({'type': 'firewall', 'policyId': int(pid), 'exists': bool(exists)}, ensure_ascii=False)
                            )
                        except Exception:
                            logger.exception('operation log write failed')
                    except Exception as e:
                        messages.error(request, f'WAF策略校验失败：{e}')
            else:
                messages.error(request, '策略ID格式不正确，请检查输入')
        else:
            form = SystemSettingsForm(instance=settings_obj)
            messages.error(request, '未知操作')
    else:
        form = SystemSettingsForm(instance=settings_obj)

    return render(request, 'admin_panel/settings.html', {
        'form': form,
        'settings_obj': settings_obj,
    })


@login_required
def plans_list(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    plans = Plan.objects.all().order_by('-is_active', 'base_price_per_domain')
    return render(request, 'admin_panel/plans_list.html', {
        'plans': plans,
    })


@login_required
def plan_create(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    if request.method == 'POST':
        form = PlanForm(request.POST)
        if form.is_valid():
            plan = form.save()
            messages.success(request, f'套餐已创建：{plan.name}')
            return redirect('admin_panel:plans')
        else:
            messages.error(request, '创建失败，请检查表单字段')
    else:
        form = PlanForm(initial={'billing_mode': 'per_domain_monthly'})
    return render(request, 'admin_panel/plan_form.html', {
        'form': form,
        'is_edit': False,
    })


@login_required
def plan_edit(request, plan_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    plan = Plan.objects.filter(id=plan_id).first()
    if not plan:
        messages.error(request, '套餐不存在')
        return redirect('admin_panel:plans')
    if request.method == 'POST':
        form = PlanForm(request.POST, instance=plan)
        if form.is_valid():
            form.save()
            messages.success(request, f'套餐已更新：{plan.name}')
            return redirect('admin_panel:plans')
        else:
            messages.error(request, '更新失败，请检查表单字段')
    else:
        form = PlanForm(instance=plan)
    return render(request, 'admin_panel/plan_form.html', {
        'form': form,
        'is_edit': True,
        'plan': plan,
    })


@login_required
@require_POST
def plan_toggle_active(request, plan_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    plan = Plan.objects.filter(id=plan_id).first()
    if not plan:
        messages.error(request, '套餐不存在')
        return redirect('admin_panel:plans')
    plan.is_active = not plan.is_active
    plan.save(update_fields=['is_active', 'updated_at'])
    messages.success(request, f'已{"启用" if plan.is_active else "禁用"}套餐：{plan.name}')
    return redirect('admin_panel:plans')


@login_required
@require_POST
def plan_toggle_public(request, plan_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    plan = Plan.objects.filter(id=plan_id).first()
    if not plan:
        messages.error(request, '套餐不存在')
        return redirect('admin_panel:plans')
    plan.is_public = not plan.is_public
    plan.save(update_fields=['is_public', 'updated_at'])
    messages.success(request, f'已设置公开状态（{"公开" if plan.is_public else "隐藏"}）：{plan.name}')
    return redirect('admin_panel:plans')


@login_required
@require_POST
def plan_toggle_allow_new(request, plan_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    plan = Plan.objects.filter(id=plan_id).first()
    if not plan:
        messages.error(request, '套餐不存在')
        return redirect('admin_panel:plans')
    plan.allow_new_purchase = not plan.allow_new_purchase
    plan.save(update_fields=['allow_new_purchase', 'updated_at'])
    messages.success(request, f'已切换允许新购：{plan.name}')
    return redirect('admin_panel:plans')


@login_required
@require_POST
def plan_toggle_allow_renew(request, plan_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    plan = Plan.objects.filter(id=plan_id).first()
    if not plan:
        messages.error(request, '套餐不存在')
        return redirect('admin_panel:plans')
    plan.allow_renew = not plan.allow_renew
    plan.save(update_fields=['allow_renew', 'updated_at'])
    messages.success(request, f'已切换允许续费：{plan.name}')
    return redirect('admin_panel:plans')


# Users management
@login_required
def users_list(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    User = get_user_model()
    q = request.GET.get('q', '').strip()
    users_qs = User.objects.all()
    if q:
        users_qs = users_qs.filter(models.Q(username__icontains=q) | models.Q(email__icontains=q))
    users = users_qs.annotate(domain_count=Count('domains')).order_by('-is_staff', '-domain_count', '-date_joined')
    return render(request, 'admin_panel/users_list.html', {
        'users': users,
        'q': q,
    })


# Domains management
@login_required
def domains_list(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    q = request.GET.get('q', '').strip()
    user_id = request.GET.get('user_id')
    status = request.GET.get('status')

    domains = Domain.objects.select_related('user', 'current_plan').all()
    if q:
        domains = domains.filter(name__icontains=q)
    if user_id:
        domains = domains.filter(user_id=user_id)
    if status:
        domains = domains.filter(status=status)

    domains = domains.order_by('-updated_at')
    # 汇总用于筛选的状态列表
    status_choices = Domain.STATUS_CHOICES
    return render(request, 'admin_panel/domains_list.html', {
        'domains': domains,
        'q': q,
        'user_id': user_id,
        'status': status,
        'status_choices': status_choices,
    })


@login_required
@require_POST
@transaction.atomic
def domain_toggle_suspend(request, domain_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    domain = Domain.objects.filter(id=domain_id).first()
    if not domain:
        messages.error(request, '域名不存在')
        return redirect('admin_panel:domains')
    if (request.POST.get('confirm') or '').strip().upper() != 'CONFIRM':
        messages.error(request, '请在确认框中输入 CONFIRM 以继续')
        return redirect('admin_panel:domains')
    if domain.status == Domain.STATUS_ACTIVE:
        domain.status = Domain.STATUS_SUSPENDED
    elif domain.status == Domain.STATUS_SUSPENDED:
        domain.status = Domain.STATUS_ACTIVE
    else:
        messages.warning(request, '当前状态不支持暂停/恢复切换')
        return redirect('admin_panel:domains')
    domain.save(update_fields=['status', 'updated_at'])
    try:
        OperationLog.objects.create(
            actor=request.user,
            action='domain_toggle_suspend',
            target=domain.name,
            detail=f"new_status={domain.status}"
        )
    except Exception:
        logger.exception('operation log write failed')
    messages.success(request, f'域名状态已切换为：{dict(Domain.STATUS_CHOICES).get(domain.status, domain.status)}')
    return redirect('admin_panel:domains')


@login_required
@transaction.atomic
def domain_switch_plan(request, domain_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    domain = Domain.objects.filter(id=domain_id).select_related('current_plan').first()
    if not domain:
        messages.error(request, '域名不存在')
        return redirect('admin_panel:domains')
    if request.method == 'POST':
        form = DomainPlanSwitchForm(request.POST, instance=domain)
        if form.is_valid():
            old_plan = domain.current_plan
            form.save()
            try:
                OperationLog.objects.create(
                    actor=request.user,
                    action='domain_switch_plan',
                    target=domain.name,
                    detail=f"{old_plan.name if old_plan else '-'} → {domain.current_plan.name if domain.current_plan else '-'}"
                )
            except Exception:
                logger.exception('operation log write failed')
            messages.success(request, f'已切换套餐：{old_plan.name if old_plan else "-"} → {domain.current_plan.name if domain.current_plan else "-"}')
            return redirect('admin_panel:domains')
        else:
            messages.error(request, '提交失败，请检查表单字段')
    else:
        form = DomainPlanSwitchForm(instance=domain)
    return render(request, 'admin_panel/domain_plan_switch.html', {
        'domain': domain,
        'form': form,
    })


# Domain: grant extra free traffic for current cycle
@login_required
@transaction.atomic
def domain_grant_traffic(request, domain_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    domain = Domain.objects.filter(id=domain_id).first()
    if not domain:
        messages.error(request, '域名不存在')
        return redirect('admin_panel:domains')
    if request.method == 'POST':
        form = DomainGrantTrafficForm(request.POST, instance=domain)
        if form.is_valid():
            form.save()
            try:
                OperationLog.objects.create(
                    actor=request.user,
                    action='domain_grant_traffic',
                    target=domain.name,
                    detail=f"extra_free_traffic_gb_current_cycle={domain.extra_free_traffic_gb_current_cycle}"
                )
            except Exception:
                logger.exception('operation log write failed')
            messages.success(request, f'已更新本周期额外赠送流量（GB）：{domain.extra_free_traffic_gb_current_cycle}')
            return redirect('admin_panel:domains')
        else:
            messages.error(request, '提交失败，请检查表单字段')
    else:
        form = DomainGrantTrafficForm(instance=domain)
    return render(request, 'admin_panel/domain_grant_traffic.html', {
        'domain': domain,
        'form': form,
    })


@login_required
@require_POST
@transaction.atomic
def domain_delete(request, domain_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    domain = Domain.objects.filter(id=domain_id).first()
    if not domain:
        messages.error(request, '域名不存在')
        return redirect('admin_panel:domains')
    if (request.POST.get('confirm') or '').strip().upper() != 'DELETE':
        messages.error(request, '请在确认框中输入 DELETE 以继续')
        return redirect('admin_panel:domains')
    domain.status = Domain.STATUS_DELETED if hasattr(Domain, 'STATUS_DELETED') else 'deleted'
    domain.save(update_fields=['status', 'updated_at'])
    try:
        OperationLog.objects.create(
            actor=request.user,
            action='domain_delete',
            target=domain.name,
            detail='soft-delete'
        )
    except Exception:
        logger.exception('operation log write failed')
    messages.success(request, '域名已标记为删除')
    return redirect('admin_panel:domains')


# Billing management (admin)
@login_required
def invoices_list(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    status = request.GET.get('status')
    user_id = request.GET.get('user_id')
    qs = Invoice.objects.select_related('user').all()
    if status:
        qs = qs.filter(status=status)
    if user_id:
        qs = qs.filter(user_id=user_id)
    qs = qs.order_by('-period_end')
    totals = qs.aggregate(total_amount=Sum('amount_total'))
    return render(request, 'admin_panel/invoices_list.html', {
        'invoices': qs,
        'status': status,
        'user_id': user_id,
        'total_amount': totals.get('total_amount') or Decimal('0.00'),
    })


@login_required
@transaction.atomic
def invoice_detail_admin(request, invoice_id: int):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    invoice = Invoice.objects.select_related('user').filter(id=invoice_id).first()
    if not invoice:
        messages.error(request, '账单不存在')
        return redirect('admin_panel:billing_list')
    adj_form = InvoiceAdjustmentForm()
    if request.method == 'POST':
        action = request.POST.get('action')
        if action == 'mark_paid' and invoice.status == Invoice.STATUS_UNPAID:
            invoice.status = Invoice.STATUS_PAID
            invoice.paid_at = timezone.now()
            invoice.save(update_fields=['status', 'paid_at'])
            try:
                OperationLog.objects.create(
                    actor=request.user,
                    action='invoice_mark_paid_admin',
                    target=f"Invoice#{invoice.id}",
                    detail=f"period={invoice.period_start}→{invoice.period_end}; amount_total={invoice.amount_total}"
                )
            except Exception:
                logger.exception('operation log write failed')
            try:
                client = GoEdgeClient()
                for it in invoice.items.select_related('domain').all():
                    if not it.domain or not it.domain.edge_server_id:
                        continue
                    web_id = client.find_server_web_id(int(it.domain.edge_server_id))
                    if web_id:
                        # 关闭停服与限速
                        client.update_http_web_shutdown(web_id, {'isOn': False})
                        client.update_http_web_request_limit(web_id, {'isOn': False})
                        # 如域名被暂停，恢复为 active
                        if it.domain.status == 'suspended':
                            it.domain.status = 'active'
                            it.domain.save(update_fields=['status', 'updated_at'])
            except Exception:
                logger.exception('auto recover after paid failed')
            messages.success(request, '账单已标记为已支付')
            return redirect('admin_panel:billing_detail', invoice_id=invoice.id)
        elif action == 'add_adjustment':
            if (request.POST.get('confirm') or '').strip().upper() != 'CONFIRM':
                messages.error(request, '请在确认框中输入 CONFIRM 以继续')
                return redirect('admin_panel:billing_detail', invoice_id=invoice.id)
            adj_form = InvoiceAdjustmentForm(request.POST)
            if adj_form.is_valid():
                adj_form.apply(invoice)
                try:
                    OperationLog.objects.create(
                        actor=request.user,
                        action='invoice_add_adjustment',
                        target=f"Invoice#{invoice.id}",
                        detail=f"adjustment={invoice.amount_adjustment}; total={invoice.amount_total}"
                    )
                except Exception:
                    logger.exception('operation log write failed')
                messages.success(request, '已添加人工调整并更新总金额')
                return redirect('admin_panel:billing_detail', invoice_id=invoice.id)
            else:
                messages.error(request, '调整提交失败，请检查表单字段')
        elif action == 'cancel' and invoice.status != Invoice.STATUS_CANCELLED:
            if (request.POST.get('confirm') or '').strip().upper() != 'CONFIRM':
                messages.error(request, '请在确认框中输入 CONFIRM 以继续')
                return redirect('admin_panel:billing_detail', invoice_id=invoice.id)
            invoice.status = Invoice.STATUS_CANCELLED
            invoice.save(update_fields=['status'])
            try:
                OperationLog.objects.create(
                    actor=request.user,
                    action='invoice_cancel',
                    target=f"Invoice#{invoice.id}",
                    detail=f"period={invoice.period_start}→{invoice.period_end}"
                )
            except Exception:
                logger.exception('operation log write failed')
            messages.success(request, '账单已取消')
            return redirect('admin_panel:billing_detail', invoice_id=invoice.id)
        elif action == 'apply_overage_policy' and invoice.status == Invoice.STATUS_UNPAID:
            if (request.POST.get('confirm') or '').strip().upper() != 'CONFIRM':
                messages.error(request, '请在确认框中输入 CONFIRM 以继续')
                return redirect('admin_panel:billing_detail', invoice_id=invoice.id)
            sys = SystemSettings.objects.order_by('id').first()
            policy = getattr(sys, 'default_overage_policy', {}) or {}
            action_type = (policy.get('action') or '').lower()
            limit_bps = int(policy.get('limit_bps') or 0)
            applied = []
            try:
                client = GoEdgeClient()
                for it in invoice.items.select_related('domain').all():
                    d = it.domain
                    if not d or not d.edge_server_id:
                        continue
                    web_id = client.find_server_web_id(int(d.edge_server_id))
                    if not web_id:
                        continue
                    if action_type == 'limit' and limit_bps > 0:
                        # 最小限速配置（简化形态）：开启限速并设定速率
                        client.update_http_web_request_limit(web_id, {'isOn': True, 'rateBytes': int(limit_bps)})
                        applied.append({'domain': d.name, 'action': 'limit', 'rateBytes': limit_bps})
                    else:
                        # 默认执行停服
                        client.update_http_web_shutdown(web_id, {'isOn': True})
                        # 域名状态置为暂停
                        if d.status != 'suspended':
                            d.status = 'suspended'
                            d.save(update_fields=['status', 'updated_at'])
                        applied.append({'domain': d.name, 'action': 'shutdown'})
                try:
                    OperationLog.objects.create(
                        actor=request.user,
                        action='apply_overage_policy',
                        target=f"Invoice#{invoice.id}",
                        detail=json.dumps({'applied': applied}, ensure_ascii=False)
                    )
                except Exception:
                    logger.exception('operation log write failed')
                messages.success(request, '已执行未支付策略（参考系统默认策略配置）')
            except Exception as e:
                messages.error(request, f'策略执行失败：{e}')
            return redirect('admin_panel:billing_detail', invoice_id=invoice.id)

    items = invoice.items.select_related('domain').all()
    return render(request, 'admin_panel/invoice_detail.html', {
        'invoice': invoice,
        'items': items,
        'adj_form': adj_form,
    })


# Quotas view: show composed quotas (global/plan/user override/domain extra)
@login_required
def quotas_view(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    user_id = request.GET.get('user_id')
    domains = Domain.objects.select_related('user', 'current_plan').all()
    if user_id:
        domains = domains.filter(user_id=user_id)
    sys = SystemSettings.objects.order_by('id').first()
    rows = []
    for d in domains:
        plan_quota = int(getattr(d.current_plan, 'included_traffic_gb_per_domain', 0) or 0)
        user_override = 0
        profile = getattr(d.user, 'profile', None)
        if profile and profile.default_free_traffic_gb_per_domain_override is not None:
            user_override = int(profile.default_free_traffic_gb_per_domain_override)
        global_default = int(sys.default_free_traffic_gb_per_domain if sys else 0)
        base_quota = plan_quota if plan_quota > 0 else (user_override if user_override > 0 else global_default)
        domain_extra = int(d.extra_free_traffic_gb_current_cycle or 0)
        total_quota = base_quota + domain_extra
        rows.append({
            'domain': d,
            'plan_quota': plan_quota,
            'user_override': user_override,
            'global_default': global_default,
            'domain_extra': domain_extra,
            'total_quota': total_quota,
        })
    rows = sorted(rows, key=lambda r: (-(r['total_quota']), r['domain'].name))
    return render(request, 'admin_panel/quotas.html', {
        'rows': rows,
        'user_id': user_id,
    })


# Monitoring: platform daily totals and top-N domains
@login_required
def monitoring_view(request):
    if not _staff_only(request):
        return HttpResponseForbidden('需要运营权限（staff）')
    from domains.models import DomainTrafficDaily
    today = timezone.now().date()
    days = int(request.GET.get('days') or 14)
    start = today - timezone.timedelta(days=days-1)
    sys = SystemSettings.objects.order_by('id').first()
    anomaly_enabled = bool(getattr(sys, 'anomaly_detection_enabled', True))
    threshold_mult = float(getattr(sys, 'anomaly_threshold_multiplier', 3.0) or 3.0)
    window_days = int(getattr(sys, 'anomaly_window_days', 7) or 7)
    min_gb = float(getattr(sys, 'anomaly_min_gb', 1.0) or 1.0)
    # 平台每日总流量
    daily = (DomainTrafficDaily.objects
             .filter(day__gte=start, day__lte=today)
             .values('day')
             .annotate(total_bytes=Sum('bytes'))
             .order_by('day'))
    daily_rows = []
    for row in daily:
        gb = round((row['total_bytes'] or 0) / (1024 ** 3), 3)
        daily_rows.append({'day': row['day'], 'gb': gb})
    # Top N 域名（本月总量）
    month_start = today.replace(day=1)
    domains = Domain.objects.all()
    top = []
    anomalies = []
    for d in domains:
        bytes_sum = DomainTrafficDaily.objects.filter(domain=d, day__gte=month_start, day__lte=today).aggregate(b=Sum('bytes'))['b'] or 0
        gb = round(bytes_sum / (1024 ** 3), 3)
        top.append({'domain': d, 'gb': gb})

        # 异常检测：今日 vs 过去窗口均值
        if anomaly_enabled:
            window_start = today - timezone.timedelta(days=window_days)
            past = (DomainTrafficDaily.objects
                    .filter(domain=d, day__gte=window_start, day__lt=today)
                    .aggregate(b=Sum('bytes'))['b'] or 0)
            past_days_count = DomainTrafficDaily.objects.filter(domain=d, day__gte=window_start, day__lt=today).count()
            past_avg_gb = 0.0
            if past_days_count > 0:
                past_avg_gb = round((past / (1024 ** 3)) / past_days_count, 3)
            today_bytes = DomainTrafficDaily.objects.filter(domain=d, day=today).aggregate(b=Sum('bytes'))['b'] or 0
            today_gb = round(today_bytes / (1024 ** 3), 3)
            trigger = False
            if past_avg_gb > 0:
                trigger = today_gb >= max(min_gb, past_avg_gb * threshold_mult)
            else:
                trigger = today_gb >= min_gb
            if trigger and today_gb > 0:
                anomalies.append({
                    'domain': d,
                    'today_gb': today_gb,
                    'past_avg_gb': past_avg_gb,
                    'ratio': round((today_gb / past_avg_gb), 2) if past_avg_gb > 0 else None,
                })
    top_sorted = sorted(top, key=lambda x: -x['gb'])[:20]
    return render(request, 'admin_panel/monitoring.html', {
        'daily_rows': daily_rows,
        'top_domains': top_sorted,
        'days': days,
        'anomalies': anomalies,
        'anomaly_config': {
            'enabled': anomaly_enabled,
            'multiplier': threshold_mult,
            'window_days': window_days,
            'min_gb': min_gb,
        },
    })
logger = logging.getLogger(__name__)