from rest_framework import serializers

from apps.calibers.models import Caliber

from .models import (
    Ammo,
    Bipod,
    Brass,
    Bullet,
    Firearm,
    Gear,
    GearStatus,
    Magazine,
    Powder,
    Primer,
    ReloadedAmmoBatch,
    ReloadRecipe,
    Rig,
    RigItem,
    Scope,
    Suppressor,
    UserGear,
    get_concrete_gear,
)


# ── Caliber helper serializer ─────────────────────────────────────────────────

class CaliberMinSerializer(serializers.ModelSerializer):
    class Meta:
        model = Caliber
        fields = ['id', 'name', 'short_name']


# ── Gear catalog serializers ──────────────────────────────────────────────────

class GearBaseSerializer(serializers.ModelSerializer):
    """Common read-only fields for every gear type (used in list views)."""

    class Meta:
        model = Gear
        fields = [
            'id', 'brand', 'model_name', 'description',
            'gear_type', 'status', 'created_at',
        ]
        read_only_fields = ['gear_type', 'status', 'created_at']


class FirearmSerializer(serializers.ModelSerializer):
    caliber = serializers.PrimaryKeyRelatedField(
        queryset=Caliber.objects.filter(status='VERIFIED'),
        required=False,
        allow_null=True,
    )
    caliber_detail = serializers.SerializerMethodField()

    def get_caliber_detail(self, obj):
        if obj.caliber_id:
            return CaliberMinSerializer(obj.caliber).data
        return None

    class Meta:
        model = Firearm
        fields = [
            'id', 'brand', 'model_name', 'description',
            'gear_type', 'status',
            'firearm_type', 'caliber', 'caliber_detail',
            'barrel_length_mm', 'magazine_capacity',
            'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at',
        ]
        read_only_fields = ['gear_type', 'status', 'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at', 'caliber_detail']


class ScopeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Scope
        fields = [
            'id', 'brand', 'model_name', 'description',
            'gear_type', 'status',
            'magnification_min', 'magnification_max',
            'objective_diameter_mm', 'tube_diameter_mm', 'reticle_type',
            'adjustment_unit', 'focal_plane',
            'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at',
        ]
        read_only_fields = ['gear_type', 'status', 'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at']


class SuppressorSerializer(serializers.ModelSerializer):
    max_caliber = serializers.PrimaryKeyRelatedField(
        queryset=Caliber.objects.filter(status='VERIFIED'),
        required=False,
        allow_null=True,
    )
    max_caliber_detail = serializers.SerializerMethodField()

    def get_max_caliber_detail(self, obj):
        if obj.max_caliber_id:
            return CaliberMinSerializer(obj.max_caliber).data
        return None

    class Meta:
        model = Suppressor
        fields = [
            'id', 'brand', 'model_name', 'description',
            'gear_type', 'status',
            'max_caliber', 'max_caliber_detail', 'thread_pitch', 'length_mm', 'weight_g',
            'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at',
        ]
        read_only_fields = ['gear_type', 'status', 'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at', 'max_caliber_detail']


class BipodSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bipod
        fields = [
            'id', 'brand', 'model_name', 'description',
            'gear_type', 'status',
            'min_height_mm', 'max_height_mm', 'attachment_type',
            'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at',
        ]
        read_only_fields = ['gear_type', 'status', 'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at']


class MagazineSerializer(serializers.ModelSerializer):
    caliber = serializers.PrimaryKeyRelatedField(
        queryset=Caliber.objects.filter(status='VERIFIED'),
        required=False,
        allow_null=True,
    )
    caliber_detail = serializers.SerializerMethodField()

    def get_caliber_detail(self, obj):
        if obj.caliber_id:
            return CaliberMinSerializer(obj.caliber).data
        return None

    class Meta:
        model = Magazine
        fields = [
            'id', 'brand', 'model_name', 'description',
            'gear_type', 'status',
            'caliber', 'caliber_detail', 'capacity',
            'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at',
        ]
        read_only_fields = ['gear_type', 'status', 'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at', 'caliber_detail']


# Maps gear_type discriminator → serializer class
_GEAR_SERIALIZER_MAP = {
    'FIREARM':    FirearmSerializer,
    'SCOPE':      ScopeSerializer,
    'SUPPRESSOR': SuppressorSerializer,
    'BIPOD':      BipodSerializer,
    'MAGAZINE':   MagazineSerializer,
}


class PolymorphicGearSerializer(serializers.BaseSerializer):
    """
    Read-only serializer that dispatches to the correct typed serializer
    based on gear_type. Used when embedding gear details in nested responses.
    """
    def to_representation(self, instance):
        concrete = get_concrete_gear(instance)
        serializer_cls = _GEAR_SERIALIZER_MAP.get(instance.gear_type, GearBaseSerializer)
        return serializer_cls(concrete, context=self.context).data


# ── User inventory serializers ────────────────────────────────────────────────

class UserGearSerializer(serializers.ModelSerializer):
    # Write: accept a gear FK (VERIFIED or user's own PENDING)
    gear = serializers.PrimaryKeyRelatedField(
        queryset=Gear.objects.none(),  # narrowed in __init__
        write_only=True,
    )
    # Read: return full typed gear details
    gear_detail = PolymorphicGearSerializer(source='gear', read_only=True)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from django.db.models import Q
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            self.fields['gear'].queryset = Gear.objects.filter(
                Q(status=GearStatus.VERIFIED) |
                Q(status=GearStatus.PENDING, submitted_by=request.user)
            )
        else:
            self.fields['gear'].queryset = Gear.objects.filter(status=GearStatus.VERIFIED)

    class Meta:
        model = UserGear
        fields = [
            'id',
            'gear',        # write
            'gear_detail', # read
            'nickname', 'serial_number', 'purchase_date', 'notes',
            'added_at',
        ]
        read_only_fields = ['added_at']


# ── Rig serializers ───────────────────────────────────────────────────────────

class RigItemReadSerializer(serializers.ModelSerializer):
    user_gear = UserGearSerializer(read_only=True)

    class Meta:
        model = RigItem
        fields = ['id', 'user_gear', 'role']


class RigItemCreateSerializer(serializers.ModelSerializer):
    """Used when adding an item to a rig (POST /rigs/{id}/items/)."""
    user_gear = serializers.PrimaryKeyRelatedField(
        queryset=UserGear.objects.none()  # narrowed to request.user in __init__
    )

    class Meta:
        model = RigItem
        fields = ['id', 'user_gear', 'role']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            self.fields['user_gear'].queryset = UserGear.objects.filter(
                user=request.user
            )

    def validate(self, attrs):
        rig = self.context['rig']
        # Build a temporary instance for clean() validation
        instance = RigItem(rig=rig, **attrs)
        instance.clean()
        return attrs

    def create(self, validated_data):
        rig = self.context['rig']
        return RigItem.objects.create(rig=rig, **validated_data)


class RigSerializer(serializers.ModelSerializer):
    rig_items = RigItemReadSerializer(many=True, read_only=True)
    primary_caliber = serializers.SerializerMethodField()

    def get_primary_caliber(self, obj):
        for item in obj.rig_items.all():
            if item.role == 'PRIMARY':
                gear = item.user_gear.gear
                # Firearm caliber lives on the MTI child table
                try:
                    firearm = gear.firearm
                    if firearm.caliber_id:
                        return {'id': firearm.caliber_id, 'name': firearm.caliber.name}
                    return None
                except Exception:
                    return None
        return None

    class Meta:
        model = Rig
        fields = ['id', 'name', 'description', 'is_public', 'primary_caliber', 'rig_items', 'created_at', 'updated_at']
        read_only_fields = ['created_at', 'updated_at']


# ── Ammo catalog serializer ───────────────────────────────────────────────────

class AmmoSerializer(serializers.ModelSerializer):
    caliber = serializers.PrimaryKeyRelatedField(
        queryset=Caliber.objects.filter(status='VERIFIED'),
        required=False,
        allow_null=True,
    )
    caliber_detail = serializers.SerializerMethodField()

    def get_caliber_detail(self, obj):
        if obj.caliber_id:
            return CaliberMinSerializer(obj.caliber).data
        return None

    class Meta:
        model = Ammo
        fields = [
            'id', 'brand', 'name', 'caliber', 'caliber_detail',
            'bullet_weight_gr', 'bullet_type',
            'primer_size', 'case_material',
            'muzzle_velocity_fps', 'muzzle_energy_ftlb',
            'box_count', 'notes', 'status',
            'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at',
        ]
        read_only_fields = ['status', 'submitted_by', 'reviewed_by', 'reviewed_at', 'created_at', 'caliber_detail']


# ── Reloading component serializers ──────────────────────────────────────────

class PrimerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Primer
        fields = ['id', 'brand', 'name', 'size', 'notes', 'status', 'submitted_by']
        read_only_fields = ['status', 'submitted_by']


class BrassSerializer(serializers.ModelSerializer):
    caliber = serializers.PrimaryKeyRelatedField(
        queryset=Caliber.objects.filter(status='VERIFIED'),
        required=False,
        allow_null=True,
    )
    caliber_detail = serializers.SerializerMethodField()

    def get_caliber_detail(self, obj):
        if obj.caliber_id:
            return CaliberMinSerializer(obj.caliber).data
        return None

    class Meta:
        model = Brass
        fields = ['id', 'brand', 'caliber', 'caliber_detail', 'primer_pocket', 'trim_length_mm', 'notes', 'status', 'submitted_by']
        read_only_fields = ['status', 'submitted_by', 'caliber_detail']


class BulletSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bullet
        fields = [
            'id', 'brand', 'model_name', 'weight_gr', 'bullet_type',
            'diameter_mm', 'length_mm', 'bc_g1', 'bc_g7',
            'status', 'submitted_by',
        ]
        read_only_fields = ['status', 'submitted_by']


class PowderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Powder
        fields = ['id', 'brand', 'name', 'powder_type', 'burn_rate_index', 'notes', 'status', 'submitted_by']
        read_only_fields = ['status', 'submitted_by']


# ── Reload development serializers ────────────────────────────────────────────

class ReloadedAmmoBatchSerializer(serializers.ModelSerializer):
    powder_detail = PowderSerializer(source='powder', read_only=True)

    class Meta:
        model = ReloadedAmmoBatch
        fields = [
            'id', 'recipe',
            'powder',         # write (PK)
            'powder_detail',  # read (nested)
            'powder_charge_gr', 'quantity',
            'oal_mm', 'coal_mm', 'crimp',
            'case_prep_notes', 'notes', 'loaded_at',
            'created_at', 'updated_at',
        ]
        read_only_fields = ['created_at', 'updated_at']


class ReloadRecipeSerializer(serializers.ModelSerializer):
    caliber = serializers.PrimaryKeyRelatedField(
        queryset=Caliber.objects.filter(status='VERIFIED'),
        required=False,
        allow_null=True,
    )
    caliber_detail = serializers.SerializerMethodField()
    primer_detail  = PrimerSerializer(source='primer', read_only=True)
    brass_detail   = BrassSerializer(source='brass',   read_only=True)
    bullet_detail  = BulletSerializer(source='bullet',  read_only=True)
    batches        = ReloadedAmmoBatchSerializer(many=True, read_only=True)

    def get_caliber_detail(self, obj):
        if obj.caliber_id:
            return CaliberMinSerializer(obj.caliber).data
        return None

    class Meta:
        model = ReloadRecipe
        fields = [
            'id', 'name', 'caliber', 'caliber_detail',
            'primer',        # write
            'primer_detail', # read
            'brass',
            'brass_detail',
            'bullet',
            'bullet_detail',
            'notes', 'is_public', 'batches',
            'created_at', 'updated_at',
        ]
        read_only_fields = ['created_at', 'updated_at', 'caliber_detail']
