from decimal import Decimal

from django.utils import timezone
from rest_framework import serializers

from shop_management.models.data.account_transaction import (
    AccountTransaction,
    AccountTransactionType,
)
from shop_management.models.data.passive_income import PassiveIncome
from shop_management.serializers.data.base import DataRootSerializer


class PassiveIncomeSerializer(DataRootSerializer):
    shop_details = serializers.SerializerMethodField()
    account_details = serializers.SerializerMethodField()
    currency_details = serializers.SerializerMethodField()

    class Meta:
        model = PassiveIncome
        fields = "__all__"
        read_only_fields = ["converted_amount"]

    def get_shop_details(self, obj):
        if obj.shop:
            return {"id": obj.shop.id, "name": obj.shop.name}
        return None

    def get_account_details(self, obj):
        if obj.account:
            return {
                "id": obj.account.id,
                "name": obj.account.name,
                "shop": obj.account.shop_id,
                "currency_id": obj.account.currency_id,
                "currency_title": obj.account.currency.title if obj.account.currency else None,
            }
        return None

    def get_currency_details(self, obj):
        if obj.currency:
            return {
                "id": obj.currency.id,
                "title": obj.currency.title,
                "shop": obj.currency.shop_id,
            }
        return None

    @staticmethod
    def _ref_prefix(income):
        return f"Passive income #{income.id}"

    def _sync_account_transaction(self, income):
        ref_prefix = self._ref_prefix(income)
        AccountTransaction.objects.filter(description__startswith=ref_prefix).delete()
        AccountTransaction.objects.create(
            account=income.account,
            account_currency=income.account.currency,
            transaction_currency=income.currency,
            transaction_type=AccountTransactionType.CREDIT,
            amount=income.amount,
            exchange_rate=income.exchange_rate,
            converted_amount=income.converted_amount,
            description=(
                f"{ref_prefix} for {income.name}"
                f"{f' | Notes: {income.notes}' if income.notes else ''}"
            ),
            transaction_date=income.income_date.date(),
        )

    def validate(self, attrs):
        income_date = attrs.get("income_date")
        if income_date is not None and timezone.is_naive(income_date):
            attrs["income_date"] = timezone.make_aware(
                income_date, timezone.get_current_timezone()
            )

        shop = attrs.get("shop") or getattr(self.instance, "shop", None)
        account = attrs.get("account") or getattr(self.instance, "account", None)
        currency = attrs.get("currency") or getattr(self.instance, "currency", None)
        name = attrs.get("name") or getattr(self.instance, "name", None)
        amount = attrs.get("amount") or getattr(self.instance, "amount", None)
        manual_rate = attrs.get("exchange_rate")

        if not name:
            raise serializers.ValidationError({"name": "Name is required."})
        if account is None:
            raise serializers.ValidationError({"account": "Account is required."})
        if currency is None:
            raise serializers.ValidationError({"currency": "Currency is required."})
        if not amount or amount <= 0:
            raise serializers.ValidationError({"amount": "Amount must be greater than 0."})

        if shop is None:
            shop = account.shop
            attrs["shop"] = shop
        if account.shop_id != shop.id:
            raise serializers.ValidationError(
                {"account": "Selected account must belong to the same shop."}
            )
        if currency.shop_id != shop.id:
            raise serializers.ValidationError(
                {"currency": "Currency must belong to the same shop."}
            )

        resolved_rate = manual_rate or AccountTransaction.resolve_exchange_rate(
            shop, currency.id, account.currency_id
        )
        if resolved_rate is None:
            raise serializers.ValidationError(
                {"exchange_rate": "No exchange rate found for the selected currencies."}
            )
        if resolved_rate <= 0:
            raise serializers.ValidationError(
                {"exchange_rate": "Exchange rate must be greater than 0."}
            )

        attrs["exchange_rate"] = Decimal(resolved_rate)
        attrs["converted_amount"] = AccountTransaction.compute_converted_amount(
            Decimal(amount), Decimal(resolved_rate)
        )
        return super().validate(attrs)

    def create(self, validated_data):
        income = super().create(validated_data)
        self._sync_account_transaction(income)
        return income

    def update(self, instance, validated_data):
        income = super().update(instance, validated_data)
        self._sync_account_transaction(income)
        return income
