"""
Сервис для работы с трансформациями товаров (Transformation).

Обеспечивает:
- Создание документов трансформации с автонумерацией
- Добавление входных/выходных товаров с автоматическим резервированием
- Проведение трансформации (FIFO списание + оприходование)
- Отмену трансформации (откат операций)
"""

from decimal import Decimal
from django.db import transaction
from django.utils import timezone
from django.core.exceptions import ValidationError

from inventory.models import (
    Transformation, TransformationInput, TransformationOutput,
    Reservation, Stock, StockBatch, DocumentCounter
)
from inventory.services.batch_manager import StockBatchManager


class TransformationService:
    """
    Сервис для работы с трансформациями товаров.
    """

    @classmethod
    def generate_document_number(cls):
        """Генерация номера документа трансформации"""
        next_num = DocumentCounter.get_next_value('transformation')
        return f"TR-{next_num:05d}"

    @classmethod
    @transaction.atomic
    def create_transformation(cls, warehouse, comment=None, employee=None):
        """
        Создать новый документ трансформации (черновик).

        Args:
            warehouse: объект Warehouse
            comment: комментарий (str, опционально)
            employee: сотрудник (User, опционально)

        Returns:
            Transformation
        """
        transformation = Transformation.objects.create(
            document_number=cls.generate_document_number(),
            warehouse=warehouse,
            status='draft',
            comment=comment or '',
            employee=employee
        )
        return transformation

    @classmethod
    @transaction.atomic
    def add_input(cls, transformation, product, quantity):
        """
        Добавить входной товар в трансформацию.
        Автоматически создает резерв (через сигнал).

        Args:
            transformation: Transformation
            product: Product
            quantity: Decimal - количество для списания

        Returns:
            TransformationInput

        Raises:
            ValidationError: если трансформация не черновик или недостаточно товара
        """
        if transformation.status != 'draft':
            raise ValidationError(
                "Нельзя добавлять позиции в проведённую или отменённую трансформацию"
            )

        quantity = Decimal(str(quantity))
        if quantity <= 0:
            raise ValidationError("Количество должно быть больше нуля")

        # Проверяем что товар еще не добавлен
        if transformation.inputs.filter(product=product).exists():
            raise ValidationError(
                f"Товар '{product.name}' уже добавлен в качестве входного"
            )

        # Проверяем доступное количество
        stock = Stock.objects.filter(
            product=product,
            warehouse=transformation.warehouse
        ).first()

        if not stock:
            raise ValidationError(
                f"Товар '{product.name}' отсутствует на складе '{transformation.warehouse.name}'"
            )

        # quantity_free = quantity_available - quantity_reserved
        available = stock.quantity_available - stock.quantity_reserved
        if quantity > available:
            raise ValidationError(
                f"Недостаточно свободного товара '{product.name}'. "
                f"Доступно: {available}, запрашивается: {quantity}"
            )

        # Создаем входной товар (резерв создастся автоматически через сигнал)
        trans_input = TransformationInput.objects.create(
            transformation=transformation,
            product=product,
            quantity=quantity
        )

        return trans_input

    @classmethod
    @transaction.atomic
    def add_output(cls, transformation, product, quantity):
        """
        Добавить выходной товар в трансформацию.

        Args:
            transformation: Transformation
            product: Product
            quantity: Decimal - количество получаемого товара

        Returns:
            TransformationOutput

        Raises:
            ValidationError: если трансформация не черновик
        """
        if transformation.status != 'draft':
            raise ValidationError(
                "Нельзя добавлять позиции в проведённую или отменённую трансформацию"
            )

        quantity = Decimal(str(quantity))
        if quantity <= 0:
            raise ValidationError("Количество должно быть больше нуля")

        # Проверяем что товар еще не добавлен
        if transformation.outputs.filter(product=product).exists():
            raise ValidationError(
                f"Товар '{product.name}' уже добавлен в качестве выходного"
            )

        # Создаем выходной товар
        trans_output = TransformationOutput.objects.create(
            transformation=transformation,
            product=product,
            quantity=quantity
        )

        return trans_output

    @classmethod
    @transaction.atomic
    def remove_input(cls, trans_input):
        """
        Удалить входной товар из трансформации.
        Автоматически освобождает резерв (через сигнал).

        Args:
            trans_input: TransformationInput

        Raises:
            ValidationError: если трансформация не черновик
        """
        if trans_input.transformation.status != 'draft':
            raise ValidationError(
                "Нельзя удалять позиции из проведённой или отменённой трансформации"
            )

        trans_input.delete()

    @classmethod
    @transaction.atomic
    def remove_output(cls, trans_output):
        """
        Удалить выходной товар из трансформации.

        Args:
            trans_output: TransformationOutput

        Raises:
            ValidationError: если трансформация не черновик
        """
        if trans_output.transformation.status != 'draft':
            raise ValidationError(
                "Нельзя удалять позиции из проведённой или отменённой трансформации"
            )

        trans_output.delete()

    @classmethod
    @transaction.atomic
    def confirm(cls, transformation):
        """
        Провести трансформацию (completed).
        FIFO списание входных товаров и оприходование выходных.
        Выполняется через сигнал process_transformation_on_complete.

        Args:
            transformation: Transformation

        Raises:
            ValidationError: если документ не готов к проведению
        """
        if transformation.status != 'draft':
            raise ValidationError("Документ уже проведён или отменён")

        if not transformation.inputs.exists():
            raise ValidationError("Добавьте хотя бы один входной товар")

        if not transformation.outputs.exists():
            raise ValidationError("Добавьте хотя бы один выходной товар")

        # Проверяем что сумма входных количеств равна сумме выходных
        total_input_quantity = sum(
            trans_input.quantity for trans_input in transformation.inputs.all()
        )
        total_output_quantity = sum(
            trans_output.quantity for trans_output in transformation.outputs.all()
        )

        if total_input_quantity != total_output_quantity:
            raise ValidationError(
                f"Сумма входных количеств ({total_input_quantity}) должна быть равна "
                f"сумме выходных количеств ({total_output_quantity})"
            )

        # Проверяем наличие всех входных товаров
        for trans_input in transformation.inputs.all():
            stock = Stock.objects.filter(
                product=trans_input.product,
                warehouse=transformation.warehouse
            ).first()

            if not stock:
                raise ValidationError(
                    f"Товар '{trans_input.product.name}' отсутствует на складе"
                )

            # Учитываем резервы (включая резерв этой трансформации)
            reserved_qty = Reservation.objects.filter(
                product=trans_input.product,
                warehouse=transformation.warehouse,
                status='reserved'
            ).exclude(
                transformation_input__transformation=transformation
            ).aggregate(total=models.Sum('quantity_base'))['total'] or Decimal('0')

            available = stock.quantity_available - reserved_qty
            if trans_input.quantity > available:
                raise ValidationError(
                    f"Недостаточно свободного товара '{trans_input.product.name}'. "
                    f"Доступно: {available}, требуется: {trans_input.quantity}"
                )

        # Меняем статус (списание и оприходование происходит через сигнал)
        transformation.status = 'completed'
        transformation.save(update_fields=['status', 'updated_at'])

        return transformation

    @classmethod
    @transaction.atomic
    def cancel(cls, transformation):
        """
        Отменить трансформацию.
        Откатывает операции если была проведена (через сигнал).

        Args:
            transformation: Transformation

        Raises:
            ValidationError: если уже отменена
        """
        if transformation.status == 'cancelled':
            raise ValidationError("Трансформация уже отменена")

        # Меняем статус (откат через сигнал если было completed)
        transformation.status = 'cancelled'
        transformation.save(update_fields=['status', 'updated_at'])

        return transformation


# Импорт models для использования в методе confirm
from django.db import models
