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

from apps.account import models as account_models
from apps.account.serializers.account_serializers import ProfileSerializer
from apps.account.serializers.user_vehicle_serializers import UserVehicleSerializer
from apps.master.serializers import master_serializers
from apps.station import models
from apps.station.serializers.station_serializers import StationMasterSerializer
from base.serializers import DynamicFieldsModelSerializer


class RatingMediaSerializer(DynamicFieldsModelSerializer):
    """
    This serializer is used to serialize and deserialize media assets associated with station rating records.

    Fields:
        id (int): The unique identifier for the media asset.
        asset (File): The media asset file (e.g., image or video).
        asset_type (str): The type or format of the media asset.

    Meta:
        model (StationRatingMedia): The model used for serialization and deserialization.
        fields (tuple): The fields to include in the serialization.
    """

    class Meta:
        model = models.StationRatingMedia
        fields = ("id", "asset", "asset_type", "is_verified")


class StationRatingSerializer(DynamicFieldsModelSerializer):
    """
    Serializer for station rating records, including associated media assets.

    Fields:
        - id (int): Unique identifier for the check-in record.
        - station (int): Identifier of the associated station.
        - user (int): Identifier of the user who made the rating.
        - rating (float): User's rating for the station.
        - label (str, optional): User-provided label or title for the rating.
        - description (str, optional): User-provided description or comment.
        - media (list of dict): List of dictionaries with media asset details.
    """

    # Media field includes a SerializerMethodField for flexible formatting
    media = serializers.SerializerMethodField(read_only=True)
    label_data = master_serializers.RatingLabelsSerializers(
        source="label", fields=["label"], read_only=True
    )
    user = ProfileSerializer(fields=["id", "name", "profile_pic"], read_only=True)

    class Meta:
        model = models.StationRating
        fields = (
            "id",
            "station",
            "user",
            "rating",
            "label",
            "description",
            "media",
            "created",
            "label_data",
        )
        read_only_fields = ["created"]
        extra_kwargs = {
            "label": {"write_only": True},
        }

    def get_media(self, obj):
        """
        Retrieve and format associated media assets.

        Args:
            obj: The station rating record.

        Returns:
            List of dictionaries with media asset details.
        """
        medias = obj.rating_station_medias.filter(is_verified=True)
        serializer = RatingMediaSerializer(medias, many=True, context=self.context)

        return serializer.data

    def validate(self, data):
        """
        Validate the presence of a label or description.

        Args:
            data: The input data to validate.

        Returns:
            Validated data.

        Raises:
            serializers.ValidationError: If both label and description are missing.
        """
        label = data.get("label")
        description = data.get("description")
        if label is None and (description is None or description == ""):
            raise serializers.ValidationError("Description field is required")
        return data


class StationCheckInCalculationSerializer(DynamicFieldsModelSerializer):
    """
    A serializer for calculating Station Check-In statistics.

    Fields:
        rating_counts (dict): Dictionary containing rating statistics for a station.
        checkin_count (int): Total number of check-ins for the station.

    Meta:
        model (StationMaster): The model used for serialization.
        fields (tuple): The fields to include in the serialization.
        read_only_fields (tuple): Fields that are read-only.
    """

    rating_counts = serializers.SerializerMethodField(read_only=True)
    checkin_count = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = models.StationMaster
        fields = ("id", "rating_counts", "checkin_count")
        read_only_fields = fields

    def get_rating_counts(self, obj):
        """
        Calculate rating statistics for a station.

        Args:
            obj (StationMaster): The StationMaster object.

        Returns:
            dict: A dictionary with rating statistics.
        """
        # Get total count of checkins for station
        total_count = obj.station_ratings.count()

        # Define rating conditions using Q objects
        conditions = [Q(rating=rating) for rating in range(1, 6)]

        # Create a dictionary to store rating statistics
        rating_stats = {
            "total_rating_count": total_count,
            "total_rating_average": round(
                obj.station_ratings.aggregate(Avg("rating"))["rating__avg"] or 0, 2
            ),
        }

        # Iterate through rating conditions and calculate statistics
        for rating, condition in enumerate(conditions, 1):
            rating_stats[f"rating_{rating}_count"] = obj.station_ratings.filter(
                condition
            ).count()

            if total_count > 0:
                average_rating = round(
                    (100 * rating_stats[f"rating_{rating}_count"]) / total_count, 2
                )
            else:
                average_rating = 0

            rating_stats[f"rating_{rating}_average"] = average_rating

        return rating_stats

    def get_checkin_count(self, obj):
        """
        Calculate the total number of check-ins for a station.

        Args:
            obj (StationMaster): The StationMaster object.

        Returns:
            int: The total number of check-ins.
        """
        total_count = obj.station_checkin.count()
        return total_count


class StationCheckInSerializer(DynamicFieldsModelSerializer):
    """
    This serializer is used to serialize and deserialize station check-in records.

    Fields:
        id (int): The unique identifier for the media asset.
        station (int): The station associated with the check-in.
        user (int): The user who performed the check-in.

    Meta:
        model (StationCheckIn): The model used for serialization and deserialization.
        fields (tuple): The fields to include in the serialization.
        read_only_fields (tuple): Fields that are read-only.
    """

    station_data = StationMasterSerializer(
        source="station",
        fields=["id", "name", "description", "coordinates", "assets"],
        read_only=True,
    )
    user_vehicle_data = UserVehicleSerializer(
        source="user_vehicle",
        fields=["id", "vehicle_number"],
        read_only=True,
    )

    class Meta:
        model = models.StationCheckIn
        fields = (
            "id",
            "station",
            "user",
            "user_vehicle",
            "created",
            "station_data",
            "user_vehicle_data",
        )
        read_only_fields = ("id", "user")
        extra_kwargs = {
            "user_vehicle": {"write_only": True},
            "station": {"write_only": True},
        }

    def __init__(self, *args, **kwargs):
        """
        Initialize the VehicleInsuranceSerializers instance.

        Dynamically filter the 'insurance_type' field queryset based on the selected 'insurance_company'.

        Args:
            *args: Variable length argument list.
            **kwargs: Arbitrary keyword arguments.
        """
        super(StationCheckInSerializer, self).__init__(*args, **kwargs)

        # Dynamic filtering of the insurance type queryset based on the selected insurance_company
        if "context" in kwargs and "request" in kwargs["context"]:
            request = kwargs["context"]["request"]
            if "user_vehicle" in request.data:
                user_vehicle = request.data["user_vehicle"]
                self.fields[
                    "user_vehicle"
                ].queryset = account_models.UserVehicle.objects.filter(
                    pk=user_vehicle,
                    user=request.user,
                )
