from datetime import date
from decimal import Decimal, ROUND_HALF_UP

from django.db import transaction
from django.utils import timezone

from apps.business.wallet.models import ConversionRule, MonthlyConversionLog, SuperCoinWallet, TDSLedger
from apps.business.wallet.services.wallet_service import WalletService


def _get_global_supercoin_defaults():
    """Return (monthly_limit, conversion_percentage) from PlatformSetting global defaults."""
    from apps.masterdata.platform_setting import PlatformSetting
    try:
        limit = Decimal(PlatformSetting.get_value("supercoin_default_monthly_limit", "0") or "0")
    except Exception:
        limit = Decimal("0")
    try:
        pct = Decimal(PlatformSetting.get_value("supercoin_default_conversion_percentage", "100") or "100")
    except Exception:
        pct = Decimal("100")
    return limit, pct


def _q(value):
    return Decimal(str(value)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)


def _get_tds_percent():
    from apps.business.withdrawals.models import WithdrawalDeductionConfig

    cfg = (
        WithdrawalDeductionConfig.objects.filter(is_active=True)
        .order_by('-updated_at')
        .first()
    )
    return Decimal(str(getattr(cfg, 'tds_percent', Decimal('5.000'))))


def apply_tds(amount):
    amount = _q(amount)
    tds_percent = _get_tds_percent()
    tds_amount = _q(amount * tds_percent / Decimal('100'))
    net_amount = _q(amount - tds_amount)
    return {
        'amount': amount,
        'tds_percent': tds_percent,
        'tds_amount': tds_amount,
        'net_amount': net_amount,
    }


def _month_first_day(now):
    return date(now.year, now.month, 1)


def _compute_allowed(monthly_limit, conversion_percentage, super_coin_balance):
    """Return the allowed conversion amount given limit/percentage/balance."""
    allowed = _q(monthly_limit or Decimal('0.00'))
    if conversion_percentage is not None:
        percentage_cap = _q(super_coin_balance * Decimal(str(conversion_percentage)) / Decimal('100'))
        allowed = min(allowed if allowed > Decimal('0.00') else percentage_cap, percentage_cap)
    return allowed


def _build_candidate_users(user=None):
    """Return list of (user_obj, monthly_limit, conversion_percentage, distributor_id) tuples."""
    from django.conf import settings as django_settings
    from django.contrib.auth import get_user_model

    global_limit, global_pct = _get_global_supercoin_defaults()
    candidates = []

    # Per-user rules (active overrides)
    per_user_qs = ConversionRule.objects.filter(is_active=True).select_related('user')
    if user is not None:
        per_user_qs = per_user_qs.filter(user=user)

    per_user_ids = set()
    for rule in per_user_qs:
        per_user_ids.add(rule.user_id)
        candidates.append((rule.user, rule.monthly_limit, rule.conversion_percentage, rule.distributor_id))

    # Global-default users (have super coins but no active per-user rule)
    if user is not None:
        if user.pk not in per_user_ids:
            dist_id = getattr(user, 'distributor_id', str(user.pk))
            candidates.append((user, global_limit, global_pct, dist_id))
    else:
        # Only process users with a non-zero super coin balance
        for sw in SuperCoinWallet.objects.filter(balance__gt=Decimal('0.00')).select_related('user').exclude(user_id__in=per_user_ids):
            dist_id = getattr(sw.user, 'distributor_id', str(sw.user_id))
            candidates.append((sw.user, global_limit, global_pct, dist_id))

    return candidates


def monthly_conversion_job(run_date=None, user=None):
    """Convert Super Coins to Main Wallet once per month under admin rules."""
    now = run_date or timezone.now().date()
    month = _month_first_day(now)

    results = []

    for (u, monthly_limit, conversion_percentage, distributor_id) in _build_candidate_users(user):
        with transaction.atomic():
            if MonthlyConversionLog.objects.filter(user=u, month=month).exists():
                continue

            super_wallet, _ = SuperCoinWallet.objects.select_for_update().get_or_create(user=u)
            if super_wallet.balance <= Decimal('0.00'):
                continue

            allowed = _compute_allowed(monthly_limit, conversion_percentage, super_wallet.balance)

            if allowed <= Decimal('0.00'):
                continue

            converted_amount = min(_q(super_wallet.balance), allowed)
            if converted_amount <= Decimal('0.00'):
                continue

            tds_calc = apply_tds(converted_amount)
            reference_id = f"SCONV_{u.pk}_{month.strftime('%Y%m')}"

            WalletService.debit_supercoins(
                user=u,
                amount=converted_amount,
                source_type='MONTHLY_CONVERSION',
                reference_id=reference_id,
                metadata={'month': month.isoformat(), 'distributor_id': distributor_id},
            )
            WalletService.credit_main_wallet(
                user=u,
                amount=tds_calc['net_amount'],
                source_type='SUPER_COIN_CONVERSION',
                reference_id=reference_id,
                distributor_id=distributor_id,
            )

            TDSLedger.objects.create(
                user=u,
                distributor_id=distributor_id,
                context=TDSLedger.Context.CONVERSION,
                gross_amount=converted_amount,
                tds_percent=tds_calc['tds_percent'],
                tds_amount=tds_calc['tds_amount'],
                reference_id=reference_id,
                month=month,
            )

            MonthlyConversionLog.objects.create(
                user=u,
                distributor_id=distributor_id,
                total_supercoins=super_wallet.balance,
                converted_amount=converted_amount,
                tds_deducted=tds_calc['tds_amount'],
                net_amount=tds_calc['net_amount'],
                month=month,
                reference_id=reference_id,
            )

            results.append(
                {
                    'user_id': str(u.pk),
                    'reference_id': reference_id,
                    'converted_amount': str(converted_amount),
                    'tds_deducted': str(tds_calc['tds_amount']),
                    'net_amount': str(tds_calc['net_amount']),
                }
            )

    return {'month': month.isoformat(), 'count': len(results), 'results': results}
