from rest_framework import serializers

from apps.knowledge_base.models import KnowledgeBase
from .models import AgentConfig, AgentGuardrail, AgentSystemTool, AgentVoiceConfig


class KnowledgeBasePkField(serializers.PrimaryKeyRelatedField):
    """
    Accepts 0 / "0" as "no knowledge base" for easier frontend integration.
    """

    def to_internal_value(self, data):
        if data in (0, "0", "", None):
            return None
        return super().to_internal_value(data)


class AgentVoiceConfigSerializer(serializers.ModelSerializer):
    class Meta:
        model = AgentVoiceConfig
        fields = [
            "voice_id",
            "tts_model_family",
            "similarity",
            "speed",
            "stability",
            "output_format",
            "streaming_latency_optimization",
            "text_normalisation_type",
            "pronunciation_dictionary_path",
        ]


class AgentConfigSerializer(serializers.ModelSerializer):
    # Avoid DRF UniqueValidator raising before we can auto-suffix the name.
    name = serializers.CharField()
    voice_config = AgentVoiceConfigSerializer(required=False, allow_null=True)
    knowledge_base = KnowledgeBasePkField(queryset=KnowledgeBase.objects.all(), required=False, allow_null=True)
    mcube_http_authorization = serializers.CharField(required=False, allow_blank=True, write_only=True)
    guardrails = serializers.ListField(child=serializers.CharField(), required=False, write_only=True)
    system_tools = serializers.ListField(child=serializers.CharField(), required=False, write_only=True)
    bot_settings = serializers.JSONField(required=False, allow_null=True, write_only=True)
    guardrails_keys = serializers.SerializerMethodField(read_only=True)
    system_tools_keys = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = AgentConfig
        fields = [
            "id",
            "name",
            "mcube_exenumber",
            "mcube_gid",
            "mcube_http_authorization",
            "stt_provider",
            "tts_provider",
            "llm_provider",
            "llm_model",
            "system_prompt",
            "default_language",
            "knowledge_base",
            "first_message_inbound",
            "first_message_outbound",
            "voice_config",
            "guardrails",
            "system_tools",
            "bot_settings",
            "guardrails_keys",
            "system_tools_keys",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_guardrails_keys(self, instance):
        return list(instance.guardrails.filter(enabled=True).values_list("guardrail_key", flat=True))

    def get_system_tools_keys(self, instance):
        return list(instance.system_tools.filter(enabled=True).values_list("tool_key", flat=True))

    def update(self, instance, validated_data):
        voice_data = validated_data.pop("voice_config", None)
        guardrails_keys = validated_data.pop("guardrails", None)
        tools_keys = validated_data.pop("system_tools", None)
        validated_data.pop("bot_settings", None)

        instance = super().update(instance, validated_data)

        if voice_data is not None:
            if voice_data is None:
                AgentVoiceConfig.objects.filter(agent_config=instance).delete()
            else:
                AgentVoiceConfig.objects.update_or_create(
                    agent_config=instance, defaults=voice_data
                )

        if guardrails_keys is not None:
            # Replace enabled set with provided keys
            AgentGuardrail.objects.filter(agent_config=instance).update(enabled=False)
            for key in guardrails_keys:
                AgentGuardrail.objects.update_or_create(
                    agent_config=instance,
                    guardrail_key=key,
                    defaults={"enabled": True},
                )

        if tools_keys is not None:
            AgentSystemTool.objects.filter(agent_config=instance).update(enabled=False)
            for key in tools_keys:
                AgentSystemTool.objects.update_or_create(
                    agent_config=instance,
                    tool_key=key,
                    defaults={"enabled": True},
                )

        return instance


class AgentConfigCreateSerializer(AgentConfigSerializer):
    def create(self, validated_data):
        voice_data = validated_data.pop("voice_config", None)
        guardrails_keys = validated_data.pop("guardrails", [])
        tools_keys = validated_data.pop("system_tools", [])
        validated_data.pop("bot_settings", None)

        # If knowledge_base is not provided (or sent as 0/"0"), create one automatically.
        kb = validated_data.get("knowledge_base", None)
        if kb is None:
            kb_name = f"{validated_data.get('name') or 'Bot'} KB"
            validated_data["knowledge_base"] = KnowledgeBase.objects.create(name=kb_name)

        # Ensure unique bot name (AgentConfig.name is globally unique in DB).
        base_name = (validated_data.get("name") or "Bot").strip() or "Bot"
        name = base_name
        if AgentConfig.objects.filter(name=name).exists():
            i = 2
            while AgentConfig.objects.filter(name=f"{base_name}-{i}").exists():
                i += 1
            name = f"{base_name}-{i}"
        validated_data["name"] = name

        agent = AgentConfig.objects.create(**validated_data)

        if voice_data:
            AgentVoiceConfig.objects.update_or_create(agent_config=agent, defaults=voice_data)

        for key in guardrails_keys:
            AgentGuardrail.objects.update_or_create(
                agent_config=agent, guardrail_key=key, defaults={"enabled": True}
            )

        for key in tools_keys:
            AgentSystemTool.objects.update_or_create(
                agent_config=agent, tool_key=key, defaults={"enabled": True}
            )

        return agent

