from datetime import date, timedelta
from decimal import Decimal, ROUND_HALF_UP

from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils import timezone
from django.contrib.auth import get_user_model

from billing.models import Invoice, InvoiceItem
from domains.models import Domain, DomainTrafficDaily
from core.models import SystemSettings


User = get_user_model()


def month_range_from_str(month_str: str):
    try:
        year, month = map(int, month_str.split('-'))
        start = date(year, month, 1)
    except Exception as e:
        raise CommandError(f"无效的 --month 参数，格式应为 YYYY-MM：{e}")
    # 下月第一天
    if month == 12:
        next_month_start = date(year + 1, 1, 1)
    else:
        next_month_start = date(year, month + 1, 1)
    end = next_month_start - timedelta(days=1)
    return start, end


def previous_month_range():
    today = timezone.now().date()
    this_month_start = today.replace(day=1)
    last_day_prev = this_month_start - timedelta(days=1)
    start_prev = last_day_prev.replace(day=1)
    return start_prev, last_day_prev


class Command(BaseCommand):
    help = "按自然月生成用户账单（套餐费 + 超量流量）。默认生成上一自然月，可用 --month 指定。"

    def add_arguments(self, parser):
        parser.add_argument('--month', type=str, help='计费月份，格式 YYYY-MM，如 2025-10')
        parser.add_argument('--user-id', type=int, help='仅为指定用户生成账单（可选）')
        parser.add_argument('--overwrite', action='store_true', help='若已存在账单则覆盖重建（删除后重建）')
        parser.add_argument('--dry-run', action='store_true', help='试运行，仅输出计算结果，不写入数据库')

    @transaction.atomic
    def handle(self, *args, **options):
        # 计费周期
        if options.get('month'):
            period_start, period_end = month_range_from_str(options['month'])
        else:
            period_start, period_end = previous_month_range()

        user_id = options.get('user_id')
        overwrite = options.get('overwrite', False)
        dry_run = options.get('dry_run', False)

        self.stdout.write(self.style.NOTICE(
            f"生成账单周期：{period_start} → {period_end}"
        ))

        users_qs = User.objects.all()
        if user_id:
            users_qs = users_qs.filter(id=user_id)
            if not users_qs.exists():
                raise CommandError(f"用户 {user_id} 不存在")

        sys = SystemSettings.objects.order_by('id').first()

        total_invoices = 0
        total_amount = Decimal('0.00')

        for user in users_qs:
            # 处理已存在账单
            existing = Invoice.objects.filter(user=user, period_start=period_start, period_end=period_end).first()
            if existing and not overwrite:
                self.stdout.write(self.style.WARNING(
                    f"跳过用户 {user.id}（{user.username}），该周期账单已存在：Invoice#{existing.id}"
                ))
                continue

            if existing and overwrite and not dry_run:
                existing.delete()
                self.stdout.write(self.style.WARNING(
                    f"已删除旧账单：用户 {user.id}（{user.username}） Invoice#{existing.id}"
                ))

            # 汇总用户域名的费用
            domains = Domain.objects.filter(user=user, status=Domain.STATUS_ACTIVE)
            amount_plan_total = Decimal('0.00')
            amount_overage_total = Decimal('0.00')
            items = []

            for d in domains:
                plan = d.current_plan
                base_price = Decimal(str(plan.base_price_per_domain)) if plan and plan.base_price_per_domain is not None else Decimal('0.00')
                included_gb = Decimal(str(plan.included_traffic_gb_per_domain)) if plan and plan.included_traffic_gb_per_domain is not None else None
                overage_price = Decimal(str(plan.overage_price_per_gb)) if plan and plan.overage_price_per_gb is not None else Decimal('0.00')

                # 若域名自定义超量单价优先
                if d.custom_overage_price_per_gb is not None:
                    overage_price = Decimal(str(d.custom_overage_price_per_gb))

                # 用户级默认免费额度覆盖
                user_default_override = None
                if hasattr(user, 'profile') and user.profile.default_free_traffic_gb_per_domain_override is not None:
                    user_default_override = Decimal(str(user.profile.default_free_traffic_gb_per_domain_override))

                # 系统全局默认
                sys_default_gb = Decimal(str(sys.default_free_traffic_gb_per_domain)) if sys and sys.default_free_traffic_gb_per_domain is not None else Decimal('0')

                # 最终基础配额：优先 Plan，其次用户覆盖，再次系统默认
                base_quota_gb = Decimal('0')
                if included_gb is not None:
                    base_quota_gb = Decimal(str(included_gb))
                elif user_default_override is not None:
                    base_quota_gb = user_default_override
                else:
                    base_quota_gb = sys_default_gb

                # 本周期域名额外赠送
                extra_gb = Decimal(str(d.extra_free_traffic_gb_current_cycle or 0))

                # 统计周期用量
                traffic_qs = DomainTrafficDaily.objects.filter(domain=d, day__gte=period_start, day__lte=period_end)
                total_bytes = sum(t.bytes for t in traffic_qs)
                used_gb = Decimal(str(total_bytes)) / Decimal('1073741824')  # 1024^3
                used_gb = used_gb.quantize(Decimal('0.001'), rounding=ROUND_HALF_UP)

                # 超量（不为负）
                over_gb = used_gb - (base_quota_gb + extra_gb)
                if over_gb < Decimal('0'):
                    over_gb = Decimal('0')
                over_gb = over_gb.quantize(Decimal('0.001'), rounding=ROUND_HALF_UP)

                # 费用累计
                if base_price > 0:
                    amount_plan_total += base_price
                    items.append({
                        'domain': d,
                        'description': '基础套餐费用',
                        'quantity': Decimal('1'),
                        'unit_price': base_price,
                        'amount': base_price,
                    })

                if over_gb > 0 and overage_price > 0:
                    over_amount = (over_gb * overage_price).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
                    amount_overage_total += over_amount
                    items.append({
                        'domain': d,
                        'description': '超量流量费用',
                        'quantity': over_gb,
                        'unit_price': overage_price,
                        'amount': over_amount,
                    })

            amount_adjustment = Decimal('0.00')
            amount_total = (amount_plan_total + amount_overage_total + amount_adjustment).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

            if dry_run:
                self.stdout.write(self.style.SUCCESS(
                    f"[DRY] 用户 {user.id}（{user.username}） 套餐费：￥{amount_plan_total} 超量费：￥{amount_overage_total} 总计：￥{amount_total}"
                ))
                continue

            # 创建账单与明细
            invoice = Invoice.objects.create(
                user=user,
                period_start=period_start,
                period_end=period_end,
                amount_plan_total=amount_plan_total,
                amount_overage_total=amount_overage_total,
                amount_adjustment=amount_adjustment,
                amount_total=amount_total,
                status='unpaid',
            )

            for it in items:
                InvoiceItem.objects.create(
                    invoice=invoice,
                    domain=it['domain'],
                    description=it['description'],
                    quantity=it['quantity'],
                    unit_price=it['unit_price'],
                    amount=it['amount'],
                )

            total_invoices += 1
            total_amount += amount_total
            self.stdout.write(self.style.SUCCESS(
                f"已生成账单：Invoice#{invoice.id} 用户 {user.id}（{user.username}） 总额：￥{amount_total}"
            ))

        self.stdout.write(self.style.SUCCESS(
            f"生成完成：共 {total_invoices} 个账单，合计金额 ￥{total_amount}"
        ))