from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from apps.transactions.models import (
    TransactionCategory,
    TransactionTag,
    TransactionEntity,
)


@extend_schema_field(
    {
        "oneOf": [{"type": "string"}, {"type": "integer"}, {"type": "null"}],
        "description": "TransactionCategory ID or name. If the name doesn't exist, a new one will be created. Can be null if no category is assigned.",
    }
)
class TransactionCategoryField(serializers.Field):
    def to_representation(self, value):
        if value is None:
            return None
        return {"id": value.id, "name": value.name}

    def to_internal_value(self, data):
        if data is None:
            return None
        if isinstance(data, int):
            try:
                return TransactionCategory.objects.get(pk=data)
            except TransactionCategory.DoesNotExist:
                raise serializers.ValidationError(
                    _("Category with this ID does not exist.")
                )
        elif isinstance(data, str):
            try:
                category = TransactionCategory.objects.get(name=data)
            except TransactionCategory.DoesNotExist:
                category = TransactionCategory(name=data)
                category.save()
            return category
        raise serializers.ValidationError(
            _("Invalid category data. Provide an ID or name.")
        )

    @staticmethod
    def get_schema():
        return {
            "type": "array",
            "items": {
                "type": "string",
                "description": "TransactionCategory ID or name",
            },
        }


@extend_schema_field(
    {
        "type": "array",
        "items": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
        "description": "TransactionTag ID or name. If the name doesn't exist, a new one will be created",
    }
)
class TransactionTagField(serializers.Field):
    def to_representation(self, value):
        return [{"id": tag.id, "name": tag.name} for tag in value.all()]

    def to_internal_value(self, data):
        tags = []
        for item in data:
            if isinstance(item, int):
                try:
                    tag = TransactionTag.objects.get(pk=item)
                except TransactionTag.DoesNotExist:
                    raise serializers.ValidationError(
                        _("Tag with this ID does not exist.")
                    )
            elif isinstance(item, str):
                try:
                    tag = TransactionTag.objects.get(name=item)
                except TransactionTag.DoesNotExist:
                    tag = TransactionTag(name=item)
                    tag.save()
            else:
                raise serializers.ValidationError(
                    _("Invalid tag data. Provide an ID or name.")
                )
            tags.append(tag)
        return tags


@extend_schema_field(
    {
        "type": "array",
        "items": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
        "description": "TransactionEntity ID or name. If the name doesn't exist, a new one will be created",
    }
)
class TransactionEntityField(serializers.Field):
    def to_representation(self, value):
        return [{"id": entity.id, "name": entity.name} for entity in value.all()]

    def to_internal_value(self, data):
        entities = []
        for item in data:
            if isinstance(item, int):
                try:
                    entity = TransactionEntity.objects.get(pk=item)
                except TransactionEntity.DoesNotExist:
                    raise serializers.ValidationError(
                        _("Entity with this ID does not exist.")
                    )
            elif isinstance(item, str):
                try:
                    entity = TransactionEntity.objects.get(name=item)
                except TransactionEntity.DoesNotExist:
                    entity = TransactionEntity(name=item)
                    entity.save()
            else:
                raise serializers.ValidationError(
                    _("Invalid entity data. Provide an ID or name.")
                )
            entities.append(entity)
        return entities
