"""
Команда управления для пересчёта себестоимости (cost_price) всех товаров.

НАЗНАЧЕНИЕ:
    Команда для разового массового пересчёта себестоимости товаров.
    В обычных условиях себестоимость обновляется автоматически через сигналы
    (inventory/signals.py: update_product_cost_on_batch_change).
    
КОГДА ИСПОЛЬЗОВАТЬ:
    - После миграции данных или массового импорта товаров
    - После изменения партий (StockBatch) напрямую в БД (минуя ORM)
    - При обнаружении расхождений между кешированной и реальной стоимостью
    - После восстановления из резервной копии или исправления данных
    - Для проверки корректности расчётов (режим --dry-run)
    
АВТОМАТИЗАЦИЯ:
    ✓ В продакшене работают сигналы - команда НЕ нужна регулярно
    ✓ Сигналы обновляют cost_price при каждом изменении партий
    ✓ См. inventory/signals.py (строки 1752-1812):
      - update_product_cost_on_batch_change (создание/изменение партии)
      - update_product_cost_on_batch_delete (удаление партии)
    ✓ Калькулятор: products/services/cost_calculator.py

ИСПОЛЬЗОВАНИЕ (multi-tenant проект):
    # Обычный запуск (сохраняет изменения в БД)
    python switch_to_tenant.py anatol recalculate_product_costs
    python switch_to_tenant.py grach recalculate_product_costs
    
    # Проверка без сохранения (безопасно - рекомендуется сначала)
    python switch_to_tenant.py anatol recalculate_product_costs --dry-run
    
    # С подробным выводом всех товаров
    python switch_to_tenant.py anatol recalculate_product_costs --verbose
    
    # Показать только изменённые товары
    python switch_to_tenant.py anatol recalculate_product_costs --only-changed
    
    # Комбинация флагов
    python switch_to_tenant.py anatol recalculate_product_costs --dry-run --verbose --only-changed
    
    # ❌ НЕПРАВИЛЬНО: python manage.py recalculate_product_costs --schema=anatol
    # ✓ ПРАВИЛЬНО: python switch_to_tenant.py anatol recalculate_product_costs

ЛОГИКА:
    Рассчитывает средневзвешенную себестоимость на основе активных партий:
    cost_price = SUM(quantity * cost_price) / SUM(quantity)
    
    Если у товара нет активных партий с остатками - cost_price = 0.00
"""

from django.core.management.base import BaseCommand
from django.db import connection
from django_tenants.management.commands import InteractiveTenantOption
from decimal import Decimal
from products.models import Product
from products.services.cost_calculator import ProductCostCalculator


class Command(InteractiveTenantOption, BaseCommand):
    help = 'Пересчитать себестоимость (cost_price) для всех товаров на основе партий StockBatch'

    def add_arguments(self, parser):
        # Добавляем --schema из InteractiveTenantOption
        super().add_arguments(parser)

        parser.add_argument(
            '--verbose',
            action='store_true',
            help='Выводить подробную информацию о каждом товаре',
        )
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Показать изменения без сохранения в БД',
        )
        parser.add_argument(
            '--only-changed',
            action='store_true',
            help='Показывать только товары с изменившейся стоимостью',
        )

    def handle(self, *args, **options):
        # Получаем тенанта из опций или интерактивно
        tenant = self.get_tenant_from_options_or_interactive(**options)

        # Устанавливаем схему тенанта
        connection.set_tenant(tenant)
        verbose = options.get('verbose', False)
        dry_run = options.get('dry_run', False)
        only_changed = options.get('only_changed', False)

        self.stdout.write(self.style.SUCCESS('\n' + '='*80))
        self.stdout.write(self.style.SUCCESS('ПЕРЕСЧЁТ СЕБЕСТОИМОСТИ ТОВАРОВ'))
        self.stdout.write(self.style.SUCCESS(f'ТЕНАНТ: {tenant.schema_name} ({tenant.name})'))
        if dry_run:
            self.stdout.write(self.style.WARNING('РЕЖИМ: DRY-RUN (БЕЗ СОХРАНЕНИЯ)'))
        self.stdout.write(self.style.SUCCESS('='*80 + '\n'))

        # Получаем все активные товары
        all_products = Product.objects.filter(status='active')
        total = all_products.count()
        updated_count = 0
        unchanged_count = 0
        with_batches_count = 0
        without_batches_count = 0

        self.stdout.write(f'Всего товаров для обработки: {total}\n')

        for product in all_products:
            # Получаем старую стоимость
            old_cost = product.cost_price

            # Рассчитываем новую стоимость
            old_cost_result, new_cost, was_updated = ProductCostCalculator.update_product_cost(
                product,
                save=not dry_run  # Сохраняем только если НЕ dry-run
            )

            # Подсчитываем статистику
            if was_updated:
                updated_count += 1
            else:
                unchanged_count += 1

            if new_cost > 0:
                with_batches_count += 1
            else:
                without_batches_count += 1

            # Выводим информацию
            if verbose or (only_changed and was_updated):
                status_symbol = '✓' if was_updated else '='
                style = self.style.SUCCESS if was_updated else self.style.WARNING

                # Получаем детали для вывода
                details = ProductCostCalculator.get_cost_details(product)
                batches_count = len(details['batches'])
                total_qty = details['total_quantity']

                self.stdout.write(
                    style(
                        f'{status_symbol} {product.sku:15} {product.name[:40]:40} | '
                        f'Старая: {old_cost:8.2f} → Новая: {new_cost:8.2f} | '
                        f'Партий: {batches_count:3}, Кол-во: {total_qty:8.2f}'
                    )
                )

        # Финальный отчет
        self.stdout.write(self.style.SUCCESS('\n' + '='*80))
        self.stdout.write(self.style.SUCCESS('РЕЗУЛЬТАТЫ:'))
        self.stdout.write(self.style.SUCCESS(f'  Всего обработано:      {total}'))
        self.stdout.write(self.style.SUCCESS(f'  Обновлено:             {updated_count}'))
        self.stdout.write(self.style.SUCCESS(f'  Без изменений:         {unchanged_count}'))
        self.stdout.write(self.style.SUCCESS(f'  С партиями (>0):       {with_batches_count}'))
        self.stdout.write(self.style.SUCCESS(f'  Без партий (=0):       {without_batches_count}'))
        if dry_run:
            self.stdout.write(self.style.WARNING('\n  ⚠ Изменения НЕ сохранены (dry-run режим)'))
        self.stdout.write(self.style.SUCCESS('='*80 + '\n'))

        if updated_count > 0:
            if dry_run:
                self.stdout.write(
                    self.style.WARNING(f'✓ Будет обновлено {updated_count} товаров при реальном запуске')
                )
            else:
                self.stdout.write(
                    self.style.SUCCESS(f'✓ Успешно обновлено {updated_count} товаров')
                )
        else:
            self.stdout.write(self.style.WARNING('Нет товаров для обновления'))
