"""
DRF serializers for billing API endpoints.
"""

from rest_framework import serializers

from smoothschedule.billing.models import AddOnFeature
from smoothschedule.billing.models import AddOnProduct
from smoothschedule.billing.models import Feature
from smoothschedule.billing.models import Invoice
from smoothschedule.billing.models import InvoiceLine
from smoothschedule.billing.models import Plan
from smoothschedule.billing.models import PlanFeature
from smoothschedule.billing.models import PlanVersion
from smoothschedule.billing.models import Subscription
from smoothschedule.billing.models import SubscriptionAddOn
from smoothschedule.billing.models import TenantCustomTier


class FeatureSerializer(serializers.ModelSerializer):
    """Serializer for Feature model."""

    depends_on_code = serializers.CharField(source='depends_on.code', read_only=True, allow_null=True)

    class Meta:
        model = Feature
        fields = [
            "id", "code", "name", "description", "feature_type",
            "category", "tenant_field_name", "display_order",
            "is_overridable", "depends_on", "depends_on_code",
        ]


class PlanSerializer(serializers.ModelSerializer):
    """Serializer for Plan model."""

    class Meta:
        model = Plan
        fields = ["id", "code", "name", "description", "display_order", "is_active"]


class PlanFeatureSerializer(serializers.ModelSerializer):
    """Serializer for PlanFeature model."""

    feature = FeatureSerializer(read_only=True)
    value = serializers.SerializerMethodField()

    class Meta:
        model = PlanFeature
        fields = ["id", "feature", "bool_value", "int_value", "value"]

    def get_value(self, obj):
        """Return the effective value based on feature type."""
        return obj.get_value()


class PlanVersionSerializer(serializers.ModelSerializer):
    """Serializer for PlanVersion model."""

    plan = PlanSerializer(read_only=True)
    features = PlanFeatureSerializer(many=True, read_only=True)
    is_available = serializers.BooleanField(read_only=True)

    class Meta:
        model = PlanVersion
        fields = [
            "id",
            "plan",
            "version",
            "name",
            "is_public",
            "is_legacy",
            "starts_at",
            "ends_at",
            "price_monthly_cents",
            "price_yearly_cents",
            # Transaction fees
            "transaction_fee_percent",
            "transaction_fee_fixed_cents",
            # Trial
            "trial_days",
            # Communication pricing (costs when feature is enabled)
            "sms_price_per_message_cents",
            "masked_calling_price_per_minute_cents",
            "proxy_number_monthly_fee_cents",
            # Credit settings
            "default_auto_reload_enabled",
            "default_auto_reload_threshold_cents",
            "default_auto_reload_amount_cents",
            # Display settings
            "is_most_popular",
            "show_price",
            "marketing_features",
            # Stripe
            "stripe_product_id",
            "stripe_price_id_monthly",
            "stripe_price_id_yearly",
            "is_available",
            # Features (entitlements via PlanFeature M2M)
            "features",
            "created_at",
        ]


class PlanVersionSummarySerializer(serializers.ModelSerializer):
    """Lightweight serializer for PlanVersion without features."""

    plan_code = serializers.CharField(source="plan.code", read_only=True)
    plan_name = serializers.CharField(source="plan.name", read_only=True)

    class Meta:
        model = PlanVersion
        fields = [
            "id",
            "plan_code",
            "plan_name",
            "version",
            "name",
            "is_legacy",
            "price_monthly_cents",
            "price_yearly_cents",
        ]


class AddOnFeatureSerializer(serializers.ModelSerializer):
    """Serializer for AddOnFeature model."""

    feature = FeatureSerializer(read_only=True)
    value = serializers.SerializerMethodField()

    class Meta:
        model = AddOnFeature
        fields = ["id", "feature", "bool_value", "int_value", "value"]

    def get_value(self, obj):
        """Return the effective value based on feature type."""
        return obj.get_value()


class AddOnProductSerializer(serializers.ModelSerializer):
    """Serializer for AddOnProduct model."""

    features = AddOnFeatureSerializer(many=True, read_only=True)

    class Meta:
        model = AddOnProduct
        fields = [
            "id",
            "code",
            "name",
            "description",
            "price_monthly_cents",
            "price_one_time_cents",
            "stripe_product_id",
            "stripe_price_id",
            "is_stackable",
            "is_active",
            "features",
        ]


class SubscriptionAddOnSerializer(serializers.ModelSerializer):
    """Serializer for SubscriptionAddOn model."""

    addon = AddOnProductSerializer(read_only=True)
    is_active = serializers.BooleanField(read_only=True)

    class Meta:
        model = SubscriptionAddOn
        fields = [
            "id",
            "addon",
            "status",
            "quantity",
            "activated_at",
            "expires_at",
            "is_active",
        ]


class SubscriptionSerializer(serializers.ModelSerializer):
    """Serializer for Subscription model."""

    plan_version = PlanVersionSummarySerializer(read_only=True)
    addons = SubscriptionAddOnSerializer(many=True, read_only=True)
    is_active = serializers.BooleanField(read_only=True)

    class Meta:
        model = Subscription
        fields = [
            "id",
            "plan_version",
            "status",
            "is_active",
            "started_at",
            "current_period_start",
            "current_period_end",
            "trial_ends_at",
            "canceled_at",
            "addons",
            "created_at",
            "updated_at",
        ]


class InvoiceLineSerializer(serializers.ModelSerializer):
    """Serializer for InvoiceLine model."""

    class Meta:
        model = InvoiceLine
        fields = [
            "id",
            "line_type",
            "description",
            "quantity",
            "unit_amount",
            "subtotal_amount",
            "tax_amount",
            "total_amount",
            "feature_code",
            "metadata",
            "created_at",
        ]


class InvoiceSerializer(serializers.ModelSerializer):
    """Serializer for Invoice model."""

    lines = InvoiceLineSerializer(many=True, read_only=True)

    class Meta:
        model = Invoice
        fields = [
            "id",
            "period_start",
            "period_end",
            "currency",
            "subtotal_amount",
            "discount_amount",
            "tax_amount",
            "total_amount",
            "status",
            "plan_code_at_billing",
            "plan_name_at_billing",
            "stripe_invoice_id",
            "created_at",
            "paid_at",
            "lines",
        ]


class InvoiceListSerializer(serializers.ModelSerializer):
    """Lightweight serializer for invoice list."""

    class Meta:
        model = Invoice
        fields = [
            "id",
            "period_start",
            "period_end",
            "total_amount",
            "status",
            "plan_name_at_billing",
            "created_at",
            "paid_at",
        ]


# =============================================================================
# Admin Serializers (for platform admin management)
# =============================================================================


class FeatureCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating/updating Features."""

    class Meta:
        model = Feature
        fields = ["code", "name", "description", "feature_type"]


class PlanCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating/updating Plans."""

    class Meta:
        model = Plan
        fields = [
            "code",
            "name",
            "description",
            "display_order",
            "is_active",
            "max_pages",
            "allow_custom_domains",
            "max_custom_domains",
        ]


class PlanFeatureWriteSerializer(serializers.Serializer):
    """Serializer for writing plan features."""

    feature_code = serializers.CharField()
    bool_value = serializers.BooleanField(required=False, allow_null=True)
    int_value = serializers.IntegerField(required=False, allow_null=True)


class PlanVersionCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating a new PlanVersion.

    Note: Features/permissions/limits are managed via PlanFeature M2M, not direct fields.
    Pass them in the 'features' array with feature_code and bool_value/int_value.
    """

    plan_code = serializers.CharField(write_only=True)
    features = PlanFeatureWriteSerializer(many=True, required=False, write_only=True)

    class Meta:
        model = PlanVersion
        fields = [
            "plan_code",
            "name",
            "is_public",
            "starts_at",
            "ends_at",
            "price_monthly_cents",
            "price_yearly_cents",
            # Transaction fees
            "transaction_fee_percent",
            "transaction_fee_fixed_cents",
            # Trial
            "trial_days",
            # Communication pricing (costs when feature is enabled)
            "sms_price_per_message_cents",
            "masked_calling_price_per_minute_cents",
            "proxy_number_monthly_fee_cents",
            # Credit settings
            "default_auto_reload_enabled",
            "default_auto_reload_threshold_cents",
            "default_auto_reload_amount_cents",
            # Display settings
            "is_most_popular",
            "show_price",
            "marketing_features",
            # Stripe
            "stripe_product_id",
            "stripe_price_id_monthly",
            "stripe_price_id_yearly",
            # Features (M2M via PlanFeature)
            "features",
        ]

    def create(self, validated_data):
        plan_code = validated_data.pop("plan_code")
        features_data = validated_data.pop("features", [])

        try:
            plan = Plan.objects.get(code=plan_code)
        except Plan.DoesNotExist:
            raise serializers.ValidationError({"plan_code": f"Plan '{plan_code}' not found"})

        # Determine next version number
        latest_version = plan.versions.order_by("-version").first()
        next_version = (latest_version.version + 1) if latest_version else 1

        # Create the version
        plan_version = PlanVersion.objects.create(
            plan=plan,
            version=next_version,
            **validated_data,
        )

        # Create plan features
        for feature_data in features_data:
            try:
                feature = Feature.objects.get(code=feature_data["feature_code"])
            except Feature.DoesNotExist:
                continue  # Skip unknown features

            PlanFeature.objects.create(
                plan_version=plan_version,
                feature=feature,
                bool_value=feature_data.get("bool_value"),
                int_value=feature_data.get("int_value"),
            )

        return plan_version


class PlanVersionUpdateSerializer(serializers.ModelSerializer):
    """Serializer for updating a PlanVersion.

    If the version has active subscribers, this will create a new version
    instead of updating in place (grandfathering).

    Note: Features/permissions/limits are managed via PlanFeature M2M, not direct fields.
    """

    features = PlanFeatureWriteSerializer(many=True, required=False, write_only=True)

    class Meta:
        model = PlanVersion
        fields = [
            "name",
            "is_public",
            "is_legacy",
            "starts_at",
            "ends_at",
            "price_monthly_cents",
            "price_yearly_cents",
            # Transaction fees
            "transaction_fee_percent",
            "transaction_fee_fixed_cents",
            # Trial
            "trial_days",
            # Communication pricing (costs when feature is enabled)
            "sms_price_per_message_cents",
            "masked_calling_price_per_minute_cents",
            "proxy_number_monthly_fee_cents",
            # Credit settings
            "default_auto_reload_enabled",
            "default_auto_reload_threshold_cents",
            "default_auto_reload_amount_cents",
            # Display settings
            "is_most_popular",
            "show_price",
            "marketing_features",
            # Stripe
            "stripe_product_id",
            "stripe_price_id_monthly",
            "stripe_price_id_yearly",
            # Features (M2M via PlanFeature)
            "features",
        ]

    def update(self, instance, validated_data):
        features_data = validated_data.pop("features", None)

        # Update the instance fields
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        # Update features if provided
        if features_data is not None:
            # Clear existing features and recreate
            instance.features.all().delete()
            for feature_data in features_data:
                try:
                    feature = Feature.objects.get(code=feature_data["feature_code"])
                except Feature.DoesNotExist:
                    continue  # Skip unknown features

                PlanFeature.objects.create(
                    plan_version=instance,
                    feature=feature,
                    bool_value=feature_data.get("bool_value"),
                    int_value=feature_data.get("int_value"),
                )

        return instance


class PlanVersionDetailSerializer(serializers.ModelSerializer):
    """Detailed serializer for PlanVersion with subscriber count.

    Note: Features/permissions/limits are in the 'features' array (PlanFeature M2M).
    """

    plan = PlanSerializer(read_only=True)
    features = PlanFeatureSerializer(many=True, read_only=True)
    is_available = serializers.BooleanField(read_only=True)
    subscriber_count = serializers.SerializerMethodField()

    class Meta:
        model = PlanVersion
        fields = [
            "id",
            "plan",
            "version",
            "name",
            "is_public",
            "is_legacy",
            "starts_at",
            "ends_at",
            "price_monthly_cents",
            "price_yearly_cents",
            # Transaction fees
            "transaction_fee_percent",
            "transaction_fee_fixed_cents",
            # Trial
            "trial_days",
            # Communication pricing (costs when feature is enabled)
            "sms_price_per_message_cents",
            "masked_calling_price_per_minute_cents",
            "proxy_number_monthly_fee_cents",
            # Credit settings
            "default_auto_reload_enabled",
            "default_auto_reload_threshold_cents",
            "default_auto_reload_amount_cents",
            # Display settings
            "is_most_popular",
            "show_price",
            "marketing_features",
            # Stripe
            "stripe_product_id",
            "stripe_price_id_monthly",
            "stripe_price_id_yearly",
            "is_available",
            # Features (M2M via PlanFeature)
            "features",
            "subscriber_count",
            "created_at",
        ]

    def get_subscriber_count(self, obj):
        """Count active subscribers on this version."""
        return Subscription.objects.filter(
            plan_version=obj,
            status__in=["active", "trial"],
        ).count()


class AddOnFeatureWriteSerializer(serializers.Serializer):
    """Serializer for writing add-on features."""

    feature_code = serializers.CharField()
    bool_value = serializers.BooleanField(required=False, allow_null=True)
    int_value = serializers.IntegerField(required=False, allow_null=True)


class AddOnProductCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating/updating AddOnProducts."""

    features = AddOnFeatureWriteSerializer(many=True, required=False, write_only=True)

    class Meta:
        model = AddOnProduct
        fields = [
            "code",
            "name",
            "description",
            "price_monthly_cents",
            "price_one_time_cents",
            "stripe_product_id",
            "stripe_price_id",
            "is_stackable",
            "is_active",
            "features",
        ]

    def create(self, validated_data):
        features_data = validated_data.pop("features", [])

        # Create the add-on
        addon = AddOnProduct.objects.create(**validated_data)

        # Create add-on features
        for feature_data in features_data:
            try:
                feature = Feature.objects.get(code=feature_data["feature_code"])
            except Feature.DoesNotExist:
                continue  # Skip unknown features

            AddOnFeature.objects.create(
                addon=addon,
                feature=feature,
                bool_value=feature_data.get("bool_value"),
                int_value=feature_data.get("int_value"),
            )

        return addon

    def update(self, instance, validated_data):
        features_data = validated_data.pop("features", None)

        # Update the instance fields
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        # Update features if provided
        if features_data is not None:
            # Clear existing features and recreate
            instance.features.all().delete()
            for feature_data in features_data:
                try:
                    feature = Feature.objects.get(code=feature_data["feature_code"])
                except Feature.DoesNotExist:
                    continue  # Skip unknown features

                AddOnFeature.objects.create(
                    addon=instance,
                    feature=feature,
                    bool_value=feature_data.get("bool_value"),
                    int_value=feature_data.get("int_value"),
                )

        return instance


class PlanWithVersionsSerializer(serializers.ModelSerializer):
    """Serializer for Plan with all its versions."""

    versions = PlanVersionDetailSerializer(many=True, read_only=True)
    active_version = serializers.SerializerMethodField()
    total_subscribers = serializers.SerializerMethodField()

    class Meta:
        model = Plan
        fields = [
            "id",
            "code",
            "name",
            "description",
            "display_order",
            "is_active",
            "max_pages",
            "allow_custom_domains",
            "max_custom_domains",
            "versions",
            "active_version",
            "total_subscribers",
        ]

    def get_active_version(self, obj):
        """Get the current active (non-legacy) version."""
        active = obj.versions.filter(is_public=True, is_legacy=False).first()
        if active:
            return PlanVersionDetailSerializer(active).data
        return None

    def get_total_subscribers(self, obj):
        """Count total subscribers across all versions."""
        return Subscription.objects.filter(
            plan_version__plan=obj,
            status__in=["active", "trial"],
        ).count()


class TenantCustomTierSerializer(serializers.ModelSerializer):
    """Serializer for TenantCustomTier model."""

    is_active = serializers.BooleanField(read_only=True)
    days_until_expiry = serializers.IntegerField(read_only=True)

    class Meta:
        model = TenantCustomTier
        fields = [
            "id",
            "features",
            "notes",
            "created_at",
            "updated_at",
            "grace_period_started_at",
            "is_active",
            "days_until_expiry",
        ]
        read_only_fields = ["id", "created_at", "updated_at", "grace_period_started_at"]
