from decimal import Decimal, InvalidOperation

from django.db import transaction
from django.utils import timezone

from .models import StockTransaction


@transaction.atomic
def create_reserves_for_plan(plan):
    """施肥計画の引当を全置換で作り直す。"""
    StockTransaction.objects.filter(
        fertilization_plan=plan,
        transaction_type=StockTransaction.TransactionType.RESERVE,
    ).delete()

    occurred_on = (
        plan.updated_at.date() if getattr(plan, 'updated_at', None) else timezone.localdate()
    )

    for entry in plan.entries.select_related('fertilizer__material'):
        material = getattr(entry.fertilizer, 'material', None)
        if material is None:
            continue
        StockTransaction.objects.create(
            material=material,
            transaction_type=StockTransaction.TransactionType.RESERVE,
            quantity=entry.bags,
            occurred_on=occurred_on,
            note=f'施肥計画「{plan.name}」からの引当',
            fertilization_plan=plan,
        )


@transaction.atomic
def delete_reserves_for_plan(plan):
    """施肥計画に紐づく引当のみ削除する。"""
    StockTransaction.objects.filter(
        fertilization_plan=plan,
        transaction_type=StockTransaction.TransactionType.RESERVE,
    ).delete()


@transaction.atomic
def confirm_spreading(plan, actual_entries):
    """引当を使用実績へ変換して施肥計画を確定済みにする。"""
    from apps.fertilizer.models import Fertilizer

    delete_reserves_for_plan(plan)

    for entry_data in actual_entries:
        actual_bags = _to_decimal(entry_data.get('actual_bags'))
        if actual_bags <= 0:
            continue

        fertilizer = (
            Fertilizer.objects.select_related('material')
            .filter(id=entry_data['fertilizer_id'])
            .first()
        )
        if fertilizer is None or fertilizer.material is None:
            continue

        StockTransaction.objects.create(
            material=fertilizer.material,
            transaction_type=StockTransaction.TransactionType.USE,
            quantity=actual_bags,
            occurred_on=timezone.localdate(),
            note=f'施肥計画「{plan.name}」散布確定',
            fertilization_plan=plan,
        )

    plan.is_confirmed = True
    plan.confirmed_at = timezone.now()
    plan.save(update_fields=['is_confirmed', 'confirmed_at'])


@transaction.atomic
def unconfirm_spreading(plan):
    """散布確定を取り消し、USE トランザクションを削除して引当を再作成する。"""
    StockTransaction.objects.filter(
        fertilization_plan=plan,
        transaction_type=StockTransaction.TransactionType.USE,
    ).delete()

    plan.is_confirmed = False
    plan.confirmed_at = None
    plan.save(update_fields=['is_confirmed', 'confirmed_at'])

    create_reserves_for_plan(plan)


def _to_decimal(value):
    try:
        return Decimal(str(value))
    except (InvalidOperation, TypeError, ValueError):
        return Decimal('0')
