from django.db.models import Q
from rest_framework import serializers

from apps.common.serializer_helpers import ammo_detail, batch_detail
from apps.gears.models import Ammo, GearStatus, ReloadedAmmoBatch, Rig
from apps.tools.models import ChronographAnalysis, ShotGroup

from .models import (
    CorrectionUnit,
    FreePracticeSession,
    PRSSession,
    PRSStage,
    SpeedShootingSession,
)


# ── Shared helpers ────────────────────────────────────────────────────────────

def _rig_detail(rig):
    if rig is None:
        return None
    return {'id': rig.id, 'name': rig.name}


# ── Abstract write mixin ──────────────────────────────────────────────────────

def _analysis_detail(analysis):
    if analysis is None:
        return None
    return {'id': analysis.id, 'name': analysis.name, 'date': str(analysis.date) if analysis.date else None}


class AbstractSessionWriteMixin:
    """
    Shared __init__ for all session write serializers:
    narrows FK querysets to the current user.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            self.fields['rig'].queryset = Rig.objects.filter(user=request.user)
            self.fields['reloaded_batch'].queryset = ReloadedAmmoBatch.objects.filter(
                recipe__user=request.user
            )
            self.fields['analysis'].queryset = ChronographAnalysis.objects.filter(
                Q(user=request.user) | Q(user__isnull=True)
            )

    def validate(self, attrs):
        user = self.context['request'].user
        instance = self.Meta.model(user=user, **attrs)
        instance.clean()
        return attrs


# ── PRS session ───────────────────────────────────────────────────────────────

class PRSStageSerializer(serializers.ModelSerializer):
    shot_group = serializers.PrimaryKeyRelatedField(
        queryset=ShotGroup.objects.none(),
        required=False, allow_null=True,
    )

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

    class Meta:
        model = PRSStage
        fields = [
            'id', 'order', 'position',
            'distance_m', 'target_width_cm', 'target_height_cm',
            'max_time_s', 'shots_count', 'notes_prep',
            'computed_elevation', 'computed_windage', 'correction_unit',
            'actual_elevation', 'actual_windage',
            'hits', 'score', 'time_taken_s',
            'shot_group', 'notes_post',
        ]
        read_only_fields = ['computed_elevation', 'computed_windage', 'correction_unit']


class PRSSessionListSerializer(serializers.ModelSerializer):
    class Meta:
        model = PRSSession
        fields = [
            'id', 'name', 'competition_name', 'category',
            'date', 'location', 'rig', 'is_public', 'created_at',
        ]


class PRSSessionWriteSerializer(AbstractSessionWriteMixin, serializers.ModelSerializer):
    rig = serializers.PrimaryKeyRelatedField(
        queryset=Rig.objects.none(),
        required=False, allow_null=True,
    )
    ammo = serializers.PrimaryKeyRelatedField(
        queryset=Ammo.objects.filter(status=GearStatus.VERIFIED),
        required=False, allow_null=True,
    )
    reloaded_batch = serializers.PrimaryKeyRelatedField(
        queryset=ReloadedAmmoBatch.objects.none(),
        required=False, allow_null=True,
    )
    analysis = serializers.PrimaryKeyRelatedField(
        queryset=ChronographAnalysis.objects.none(),
        required=False, allow_null=True,
    )

    class Meta:
        model = PRSSession
        fields = [
            'id', 'name', 'competition_name', 'category',
            'date', 'location',
            'rig', 'ammo', 'reloaded_batch', 'analysis',
            'temperature_c', 'wind_speed_ms', 'wind_direction_deg',
            'humidity_pct', 'pressure_hpa', 'weather_notes',
            'notes', 'is_public',
        ]


class PRSSessionDetailSerializer(serializers.ModelSerializer):
    rig_detail            = serializers.SerializerMethodField()
    ammo_detail           = serializers.SerializerMethodField()
    reloaded_batch_detail = serializers.SerializerMethodField()
    analysis_detail       = serializers.SerializerMethodField()
    stages                = PRSStageSerializer(many=True, read_only=True)

    def get_rig_detail(self, obj):
        return _rig_detail(obj.rig)

    def get_ammo_detail(self, obj):
        return ammo_detail(obj.ammo)

    def get_reloaded_batch_detail(self, obj):
        return batch_detail(obj.reloaded_batch)

    def get_analysis_detail(self, obj):
        return _analysis_detail(obj.analysis)

    class Meta:
        model = PRSSession
        fields = [
            'id', 'name', 'competition_name', 'category',
            'date', 'location',
            'rig', 'rig_detail',
            'ammo', 'ammo_detail',
            'reloaded_batch', 'reloaded_batch_detail',
            'analysis', 'analysis_detail',
            'temperature_c', 'wind_speed_ms', 'wind_direction_deg',
            'humidity_pct', 'pressure_hpa', 'weather_notes',
            'notes', 'is_public', 'stages',
            'created_at', 'updated_at',
        ]


# ── Free Practice session ─────────────────────────────────────────────────────

class FreePracticeSessionListSerializer(serializers.ModelSerializer):
    class Meta:
        model = FreePracticeSession
        fields = ['id', 'name', 'date', 'location', 'distance_m', 'rounds_fired', 'rig', 'is_public', 'created_at']


class FreePracticeSessionWriteSerializer(AbstractSessionWriteMixin, serializers.ModelSerializer):
    rig = serializers.PrimaryKeyRelatedField(
        queryset=Rig.objects.none(),
        required=False, allow_null=True,
    )
    ammo = serializers.PrimaryKeyRelatedField(
        queryset=Ammo.objects.filter(status=GearStatus.VERIFIED),
        required=False, allow_null=True,
    )
    reloaded_batch = serializers.PrimaryKeyRelatedField(
        queryset=ReloadedAmmoBatch.objects.none(),
        required=False, allow_null=True,
    )
    analysis = serializers.PrimaryKeyRelatedField(
        queryset=ChronographAnalysis.objects.none(),
        required=False, allow_null=True,
    )

    class Meta:
        model = FreePracticeSession
        fields = [
            'id', 'name', 'date', 'location',
            'rig', 'ammo', 'reloaded_batch', 'analysis',
            'distance_m', 'target_description', 'rounds_fired',
            'temperature_c', 'wind_speed_ms', 'wind_direction_deg',
            'humidity_pct', 'pressure_hpa', 'weather_notes',
            'notes', 'is_public',
        ]


class FreePracticeSessionDetailSerializer(serializers.ModelSerializer):
    rig_detail            = serializers.SerializerMethodField()
    ammo_detail           = serializers.SerializerMethodField()
    reloaded_batch_detail = serializers.SerializerMethodField()
    analysis_detail       = serializers.SerializerMethodField()

    def get_rig_detail(self, obj):
        return _rig_detail(obj.rig)

    def get_ammo_detail(self, obj):
        return ammo_detail(obj.ammo)

    def get_reloaded_batch_detail(self, obj):
        return batch_detail(obj.reloaded_batch)

    def get_analysis_detail(self, obj):
        return _analysis_detail(obj.analysis)

    class Meta:
        model = FreePracticeSession
        fields = [
            'id', 'name', 'date', 'location',
            'rig', 'rig_detail',
            'ammo', 'ammo_detail',
            'reloaded_batch', 'reloaded_batch_detail',
            'analysis', 'analysis_detail',
            'distance_m', 'target_description', 'rounds_fired',
            'temperature_c', 'wind_speed_ms', 'wind_direction_deg',
            'humidity_pct', 'pressure_hpa', 'weather_notes',
            'notes', 'is_public', 'created_at', 'updated_at',
        ]


# ── Speed Shooting session ────────────────────────────────────────────────────

class SpeedShootingSessionListSerializer(serializers.ModelSerializer):
    class Meta:
        model = SpeedShootingSession
        fields = ['id', 'name', 'format', 'date', 'location', 'rounds_fired', 'rig', 'is_public', 'created_at']


class SpeedShootingSessionWriteSerializer(AbstractSessionWriteMixin, serializers.ModelSerializer):
    rig = serializers.PrimaryKeyRelatedField(
        queryset=Rig.objects.none(),
        required=False, allow_null=True,
    )
    ammo = serializers.PrimaryKeyRelatedField(
        queryset=Ammo.objects.filter(status=GearStatus.VERIFIED),
        required=False, allow_null=True,
    )
    reloaded_batch = serializers.PrimaryKeyRelatedField(
        queryset=ReloadedAmmoBatch.objects.none(),
        required=False, allow_null=True,
    )
    analysis = serializers.PrimaryKeyRelatedField(
        queryset=ChronographAnalysis.objects.none(),
        required=False, allow_null=True,
    )

    class Meta:
        model = SpeedShootingSession
        fields = [
            'id', 'name', 'format', 'date', 'location',
            'rig', 'ammo', 'reloaded_batch', 'analysis',
            'rounds_fired',
            'temperature_c', 'wind_speed_ms', 'wind_direction_deg',
            'humidity_pct', 'pressure_hpa', 'weather_notes',
            'notes', 'is_public',
        ]


class SpeedShootingSessionDetailSerializer(serializers.ModelSerializer):
    rig_detail            = serializers.SerializerMethodField()
    ammo_detail           = serializers.SerializerMethodField()
    reloaded_batch_detail = serializers.SerializerMethodField()
    analysis_detail       = serializers.SerializerMethodField()

    def get_rig_detail(self, obj):
        return _rig_detail(obj.rig)

    def get_ammo_detail(self, obj):
        return ammo_detail(obj.ammo)

    def get_reloaded_batch_detail(self, obj):
        return batch_detail(obj.reloaded_batch)

    def get_analysis_detail(self, obj):
        return _analysis_detail(obj.analysis)

    class Meta:
        model = SpeedShootingSession
        fields = [
            'id', 'name', 'format', 'date', 'location',
            'rig', 'rig_detail',
            'ammo', 'ammo_detail',
            'reloaded_batch', 'reloaded_batch_detail',
            'analysis', 'analysis_detail',
            'rounds_fired',
            'temperature_c', 'wind_speed_ms', 'wind_direction_deg',
            'humidity_pct', 'pressure_hpa', 'weather_notes',
            'notes', 'is_public', 'created_at', 'updated_at',
        ]
