from decimal import Decimal

from rest_framework import serializers

from shop_management.models.data.account_transaction import (
    AccountTransaction,
    AccountTransactionType,
)
from shop_management.models.data.shop_account import Account
from shop_management.models.data.utils import Currency
from shop_management.serializers.data.base import DataRootSerializer


class AccountTransactionSerializer(DataRootSerializer):
    account_name = serializers.ReadOnlyField(source="account.name")
    shop = serializers.ReadOnlyField(source="account.shop_id")
    shop_name = serializers.ReadOnlyField(source="account.shop.name")
    account_currency_title = serializers.ReadOnlyField(source="account_currency.title")
    transaction_currency_title = serializers.ReadOnlyField(
        source="transaction_currency.title"
    )
    created_by_name = serializers.SerializerMethodField()
    reversed_by_name = serializers.SerializerMethodField()
    is_reversed = serializers.ReadOnlyField()

    class Meta:
        model = AccountTransaction
        fields = [
            "id",
            "account",
            "account_name",
            "shop",
            "shop_name",
            "account_currency",
            "account_currency_title",
            "transaction_currency",
            "transaction_currency_title",
            "transaction_type",
            "amount",
            "exchange_rate",
            "converted_amount",
            "description",
            "reference",
            "source_type",
            "source_id",
            "is_system_generated",
            "created_by",
            "created_by_name",
            "reversed_transaction",
            "reversed_at",
            "reversed_by",
            "reversed_by_name",
            "reversal_reason",
            "is_reversed",
            "transaction_date",
            "created_at",
            "updated_at",
        ]
        read_only_fields = [
            "account_currency",
            "exchange_rate",
            "converted_amount",
            "source_type",
            "source_id",
            "is_system_generated",
            "created_by",
            "reversed_transaction",
            "reversed_at",
            "reversed_by",
            "reversal_reason",
            "created_at",
            "updated_at",
        ]

    def get_created_by_name(self, obj):
        user = obj.created_by
        if not user:
            return "Legacy / unknown"
        return user.get_full_name() or user.username

    def get_reversed_by_name(self, obj):
        user = obj.reversed_by
        if not user:
            return ""
        return user.get_full_name() or user.username

    def validate(self, attrs):
        account = attrs.get("account") or getattr(self.instance, "account", None)
        txn_currency = attrs.get("transaction_currency") or getattr(
            self.instance, "transaction_currency", None
        )
        amount = attrs.get("amount") or getattr(self.instance, "amount", None)
        txn_type = attrs.get("transaction_type") or getattr(
            self.instance, "transaction_type", None
        )

        if not account:
            raise serializers.ValidationError({"account": "Account is required."})
        if not txn_currency:
            raise serializers.ValidationError(
                {"transaction_currency": "Transaction currency is required."}
            )
        if not amount or amount <= 0:
            raise serializers.ValidationError({"amount": "Amount must be greater than 0."})
        if txn_type not in [AccountTransactionType.CREDIT, AccountTransactionType.DEBIT]:
            raise serializers.ValidationError(
                {"transaction_type": "Transaction type must be credit or debit."}
            )

        description = str(attrs.get("description") or getattr(self.instance, "description", "") or "").strip()
        if not self.instance and not description:
            raise serializers.ValidationError(
                {"description": "Explain why this manual money movement is being recorded."}
            )

        if txn_currency.shop_id != account.shop_id:
            raise serializers.ValidationError(
                {"transaction_currency": "Currency must belong to the account shop."}
            )

        resolved_rate = AccountTransaction.resolve_exchange_rate(
            account.shop, txn_currency.id, account.currency_id
        )
        if resolved_rate is None:
            raise serializers.ValidationError(
                {
                    "transaction_currency": (
                        "No exchange rate found between transaction currency and "
                        "account currency for this shop."
                    )
                }
            )

        attrs["account_currency"] = account.currency
        attrs["exchange_rate"] = Decimal(resolved_rate)
        attrs["converted_amount"] = AccountTransaction.compute_converted_amount(
            Decimal(amount), Decimal(resolved_rate)
        )
        return attrs
