from django.shortcuts import render
import logging
from django.contrib.auth.decorators import login_required
from django.db.models import Sum
from django.shortcuts import get_object_or_404, redirect
from django.utils import timezone
from django.contrib import messages

from .models import Invoice
from domains.models import DomainTrafficDaily
from decimal import Decimal
from core.models import OperationLog
from core.models import SystemSettings
from django.http import HttpResponse
import hashlib
import urllib.parse


@login_required
def list_billing(request):
    status = request.GET.get('status')
    invoices_qs = Invoice.objects.filter(user=request.user)
    if status:
        invoices_qs = invoices_qs.filter(status=status)
    invoices = invoices_qs.order_by('-period_end')
    totals = invoices_qs.aggregate(total_amount=Sum('amount_total'))
    return render(request, 'billing/list.html', {
        'invoices': invoices,
        'total_amount': totals.get('total_amount') or 0,
        'status': status or '',
        'status_choices': getattr(Invoice, 'STATUS_CHOICES', []),
    })


@login_required
def invoice_detail(request, invoice_id: int):
    invoice = get_object_or_404(Invoice, id=invoice_id)
    # 权限：仅本人或staff可查看
    if not (invoice.user_id == request.user.id or request.user.is_staff):
        return redirect('billing:list')

    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',
                    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')
            messages.success(request, '账单已标记为已支付。')
            return redirect('billing:detail', invoice_id=invoice.id)

    items = invoice.items.select_related('domain').all()
    plan_total = invoice.amount_plan_total
    overage_total = invoice.amount_overage_total
    adjustment = invoice.amount_adjustment
    amount_total = invoice.amount_total
    # 聚合账单周期内的域名用量（GB）
    traffic_by_domain = {}
    domain_stats = []
    period_start = invoice.period_start
    period_end = invoice.period_end
    for it in items:
        if it.domain_id and it.domain_id not in traffic_by_domain:
            bytes_sum = DomainTrafficDaily.objects.filter(domain_id=it.domain_id, day__gte=period_start, day__lte=period_end).aggregate(b=Sum('bytes'))['b'] or 0
            gb = round(Decimal(str(bytes_sum)) / Decimal(str(1024 ** 3)), 3)
            traffic_by_domain[it.domain_id] = gb
            domain_stats.append({'domain': it.domain, 'gb': gb})
    return render(request, 'billing/detail.html', {
        'invoice': invoice,
        'items': items,
        'plan_total': plan_total,
        'overage_total': overage_total,
        'adjustment': adjustment,
        'amount_total': amount_total,
        'traffic_by_domain': traffic_by_domain,
        'domain_stats': domain_stats,
        'period_start': period_start,
        'period_end': period_end,
    })


@login_required
def invoice_pay(request, invoice_id: int):
    invoice = get_object_or_404(Invoice, id=invoice_id, user=request.user)
    if invoice.status != Invoice.STATUS_UNPAID:
        return redirect('billing:detail', invoice_id=invoice.id)
    settings_obj = SystemSettings.objects.order_by('id').first()
    api = (settings_obj.epay_api_base_url or '').rstrip('/')
    pid = settings_obj.epay_pid or ''
    key = settings_obj.epay_key or ''
    if not (api and pid and key):
        messages.error(request, '支付未配置')
        return redirect('billing:detail', invoice_id=invoice.id)
    pay_type = request.GET.get('type') or 'alipay'
    params = {
        'pid': pid,
        'type': pay_type,
        'out_trade_no': f'INV{invoice.id}',
        'notify_url': request.build_absolute_uri(reverse('billing:notify')),
        'return_url': request.build_absolute_uri(reverse('billing:return')),
        'name': f'Invoice#{invoice.id}',
        'money': str(invoice.amount_total),
        'sitename': 'PyGoEdge',
        'sign_type': 'MD5',
    }
    sign_src = '&'.join(f"{k}={params[k]}" for k in sorted(params) if k not in ['sign', 'sign_type'] and params[k] != '') + '&key=' + key
    sign = hashlib.md5(sign_src.encode('utf-8')).hexdigest().upper()
    params['sign'] = sign
    url = api + '/submit.php?' + urllib.parse.urlencode(params)
    try:
        OperationLog.objects.create(actor=request.user, action='invoice_pay_create', target=f'Invoice#{invoice.id}', detail=url)
    except Exception:
        pass
    return redirect(url)


def _verify_epay_sign(params: dict, key: str) -> bool:
    p = {k: v for k, v in params.items() if k not in ['sign', 'sign_type'] and v is not None and v != ''}
    src = '&'.join(f"{k}={p[k]}" for k in sorted(p)) + '&key=' + key
    calc = hashlib.md5(src.encode('utf-8')).hexdigest().upper()
    return calc == (params.get('sign') or '').upper()


def payment_notify(request):
    settings_obj = SystemSettings.objects.order_by('id').first()
    key = settings_obj.epay_key or ''
    params = dict(request.GET.items())
    ok = (_verify_epay_sign(params, key) if key else False)
    out_trade_no = params.get('out_trade_no') or ''
    trade_status = params.get('trade_status') or ''
    money = params.get('money') or ''
    if ok and out_trade_no.startswith('INV') and trade_status:
        inv_id = int(out_trade_no.replace('INV', ''))
        inv = Invoice.objects.filter(id=inv_id).first()
        if inv and inv.status == Invoice.STATUS_UNPAID:
            if str(inv.amount_total) == str(money):
                inv.status = Invoice.STATUS_PAID
                inv.paid_at = timezone.now()
                inv.save(update_fields=['status', 'paid_at'])
                try:
                    OperationLog.objects.create(actor=None, action='invoice_paid_notify', target=f'Invoice#{inv.id}', detail=out_trade_no)
                except Exception:
                    pass
                return HttpResponse('SUCCESS')
    return HttpResponse('FAIL')


@login_required
def payment_return(request):
    messages.info(request, '支付流程已完成，如账单仍显示未支付，请稍后或刷新页面。')
    return redirect('billing:list')


@login_required
def invoice_detail_csv(request, invoice_id: int):
    invoice = get_object_or_404(Invoice, id=invoice_id)
    if not (invoice.user_id == request.user.id or request.user.is_staff):
        return redirect('billing:list')
    import csv
    from django.http import HttpResponse
    response = HttpResponse(content_type='text/csv; charset=utf-8')
    response['Content-Disposition'] = f'attachment; filename="invoice_{invoice.id}.csv"'
    writer = csv.writer(response)
    writer.writerow(['Domain', 'Description', 'Quantity(GB)', 'Unit Price', 'Amount'])
    for it in invoice.items.select_related('domain').all():
        writer.writerow([
            it.domain.name if it.domain else '',
            it.description,
            str(it.quantity),
            str(it.unit_price),
            str(it.amount),
        ])
    return response

# Create your views here.
logger = logging.getLogger(__name__)
