"""
Admin portal serializers — maps PHP admin page data structures to DRF serializers.
"""
from decimal import Decimal
from rest_framework import serializers
from apps.core.models import (
    User, Package, Rank, Investment, Transaction, Pin,
    MatchingSchedule, Genealogy, CronLog
)


# ──────────────────────────────────────────────
# Auth
# ──────────────────────────────────────────────

class AdminLoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField(write_only=True)


# ──────────────────────────────────────────────
# Dashboard
# ──────────────────────────────────────────────

class DashboardStatsSerializer(serializers.Serializer):
    total_members = serializers.IntegerField()
    total_business_volume = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_roi_paid = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_withdrawals = serializers.DecimalField(max_digits=15, decimal_places=2)
    active_plans = serializers.IntegerField()
    available_pins = serializers.IntegerField()


class RecentTransactionSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user.username', read_only=True)
    formatted_date = serializers.SerializerMethodField()

    class Meta:
        model = Transaction
        fields = ['id', 'username', 'type', 'amount', 'description', 'created_at', 'formatted_date']

    def get_formatted_date(self, obj):
        return obj.created_at.strftime('%Y-%m-%d %H:%M')


# ──────────────────────────────────────────────
# Members
# ──────────────────────────────────────────────

class MemberListSerializer(serializers.ModelSerializer):
    rank_name = serializers.SerializerMethodField()
    packages_info = serializers.SerializerMethodField()
    formatted_address = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = [
            'id', 'mid', 'username', 'email', 'phone', 'full_name',
            'rank_id', 'rank_name', 'total_investment', 'status',
            'created_at', 'packages_info', 'formatted_address',
            'address', 'state', 'country',
        ]

    def get_rank_name(self, obj):
        if obj.rank_id > 0:
            ranks = self.context.get('ranks', [])
            idx = obj.rank_id - 1
            if 0 <= idx < len(ranks):
                return ranks[idx].name
        return 'None'

    def get_packages_info(self, obj):
        investments = obj.investments.select_related('package').all()
        if not investments:
            return 'None'
        return ', '.join(
            f"{inv.package.name} (${inv.amount:,.2f})" for inv in investments
        )

    def get_formatted_address(self, obj):
        parts = [obj.address or '', obj.state or '', obj.country or '']
        full = ' '.join(p for p in parts if p).strip()
        return full or 'Not Provided'


class MemberStatusUpdateSerializer(serializers.Serializer):
    status = serializers.ChoiceField(choices=['active', 'suspended', 'inactive'])


class BulkDeleteSerializer(serializers.Serializer):
    ids = serializers.ListField(child=serializers.IntegerField())


# ──────────────────────────────────────────────
# Packages
# ──────────────────────────────────────────────

class PackageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Package
        fields = ['id', 'name', 'amount', 'created_at']


class PackageCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Package
        fields = ['name', 'amount']


# ──────────────────────────────────────────────
# PINs
# ──────────────────────────────────────────────

class PinListSerializer(serializers.ModelSerializer):
    package_name = serializers.CharField(source='package.name', read_only=True)
    package_amount = serializers.DecimalField(source='package.amount', max_digits=15, decimal_places=2, read_only=True)
    assigned_to_user = serializers.SerializerMethodField()
    assigned_to_mid = serializers.SerializerMethodField()
    used_by_user = serializers.SerializerMethodField()
    used_by_mid = serializers.SerializerMethodField()
    formatted_date = serializers.SerializerMethodField()

    class Meta:
        model = Pin
        fields = [
            'id', 'pin_code', 'package_name', 'package_amount', 'status',
            'assigned_to_user', 'assigned_to_mid',
            'used_by_user', 'used_by_mid',
            'created_at', 'formatted_date',
        ]

    def get_assigned_to_user(self, obj):
        return obj.assigned_to.username if obj.assigned_to else None

    def get_assigned_to_mid(self, obj):
        return obj.assigned_to.mid if obj.assigned_to else None

    def get_used_by_user(self, obj):
        return obj.used_by.username if obj.used_by else None

    def get_used_by_mid(self, obj):
        return obj.used_by.mid if obj.used_by else None

    def get_formatted_date(self, obj):
        return obj.created_at.strftime('%Y-%m-%d %H:%M')


class PinGenerateSerializer(serializers.Serializer):
    package_id = serializers.IntegerField()
    count = serializers.IntegerField(min_value=1, max_value=100)
    assign_username = serializers.CharField(required=False, allow_blank=True, default='')


# ──────────────────────────────────────────────
# Withdrawals
# ──────────────────────────────────────────────

class WithdrawalListSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user.username', read_only=True)
    user_mid = serializers.CharField(source='user.mid', read_only=True)
    formatted_date = serializers.SerializerMethodField()

    class Meta:
        model = Transaction
        fields = [
            'id', 'created_at', 'formatted_date', 'username', 'user_mid',
            'amount', 'fee', 'net_amount', 'status', 'description',
        ]

    def get_formatted_date(self, obj):
        return obj.created_at.strftime('%Y-%m-%d %H:%M:%S')


# ──────────────────────────────────────────────
# Reports
# ──────────────────────────────────────────────

class BusinessReportsSerializer(serializers.Serializer):
    # Inflow vs Outflow
    total_inflow = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_roi = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_level = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_rank = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_outflow = serializers.DecimalField(max_digits=15, decimal_places=2)
    net_reserve_health = serializers.DecimalField(max_digits=15, decimal_places=2)

    # PIN Ledger
    used_pins_count = serializers.IntegerField()
    used_pins_value = serializers.DecimalField(max_digits=15, decimal_places=2)
    unused_pins_count = serializers.IntegerField()
    unused_pins_value = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_minted_value = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_pins_count = serializers.IntegerField()

    # Liability & Cap
    active_investment = serializers.DecimalField(max_digits=15, decimal_places=2)
    max_passive_liability = serializers.DecimalField(max_digits=15, decimal_places=2)
    passive_roi_paid = serializers.DecimalField(max_digits=15, decimal_places=2)
    remaining_passive_liability = serializers.DecimalField(max_digits=15, decimal_places=2)
    passive_progress_percent = serializers.FloatField()
    total_user_investment = serializers.DecimalField(max_digits=15, decimal_places=2)
    max_global_id_cap = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_incomes_paid = serializers.DecimalField(max_digits=15, decimal_places=2)
    remaining_global_id_cap = serializers.DecimalField(max_digits=15, decimal_places=2)
    global_id_cap_progress = serializers.FloatField()

    # Fee & Withdrawal
    total_requested_withdrawals = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_withdrawal_fees = serializers.DecimalField(max_digits=15, decimal_places=2)
    net_paid_withdrawals = serializers.DecimalField(max_digits=15, decimal_places=2)
    withdrawal_count = serializers.IntegerField()


# ──────────────────────────────────────────────
# Matching Schedules
# ──────────────────────────────────────────────

class MatchingScheduleSerializer(serializers.ModelSerializer):
    achiever_username = serializers.CharField(source='user.username', read_only=True)
    achiever_mid = serializers.CharField(source='user.mid', read_only=True)
    achiever_fullname = serializers.CharField(source='user.full_name', read_only=True)
    achiever_email = serializers.CharField(source='user.email', read_only=True)
    rank_name = serializers.SerializerMethodField()
    sponsor_username = serializers.SerializerMethodField()
    sponsor_mid = serializers.SerializerMethodField()
    placement_username = serializers.SerializerMethodField()
    placement_mid = serializers.SerializerMethodField()
    left_child = serializers.SerializerMethodField()
    right_child = serializers.SerializerMethodField()
    formatted_date = serializers.SerializerMethodField()

    class Meta:
        model = MatchingSchedule
        fields = [
            'id', 'slab_amount', 'daily_income', 'days_passed', 'max_days',
            'status', 'created_at', 'formatted_date',
            'achiever_username', 'achiever_mid', 'achiever_fullname', 'achiever_email',
            'rank_name',
            'sponsor_username', 'sponsor_mid',
            'placement_username', 'placement_mid',
            'left_child', 'right_child',
        ]

    def get_rank_name(self, obj):
        from apps.core.models import Rank
        rank = Rank.objects.filter(matching_business=obj.slab_amount).first()
        return rank.name if rank else 'None (Slab Achieved)'

    def get_sponsor_username(self, obj):
        return obj.user.sponsor.username if obj.user.sponsor else None

    def get_sponsor_mid(self, obj):
        return obj.user.sponsor.mid if obj.user.sponsor else None

    def get_placement_username(self, obj):
        return obj.user.placement.username if obj.user.placement else None

    def get_placement_mid(self, obj):
        return obj.user.placement.mid if obj.user.placement else None

    def get_left_child(self, obj):
        child = User.objects.filter(placement=obj.user, position='left').first()
        if child:
            return {'username': child.username, 'mid': child.mid}
        return None

    def get_right_child(self, obj):
        child = User.objects.filter(placement=obj.user, position='right').first()
        if child:
            return {'username': child.username, 'mid': child.mid}
        return None

    def get_formatted_date(self, obj):
        return obj.created_at.strftime('%Y-%m-%d %H:%M')
