from decimal import Decimal

from django.core.management.base import BaseCommand
from django.db import transaction

from shop_management.models.data.stock import Stock
from shop_management.models.data.stock_transfer import StockTransfer
from shop_management.views.data.stock import StockTransferViewSet, resolve_shop_currency


class Command(BaseCommand):
    help = (
        "Repair accepted stock transfers whose destination stock is hidden from "
        "the Stock list (missing/deleted purchase_item, or wrong product name "
        "from code-only matching)."
    )

    def add_arguments(self, parser):
        parser.add_argument(
            "--shop",
            type=int,
            help="Only repair transfers into this destination shop id.",
        )
        parser.add_argument(
            "--product-name",
            type=str,
            help="Only repair transfers whose source product name contains this text.",
        )
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Show what would change without writing.",
        )

    def handle(self, *args, **options):
        shop_id = options.get("shop")
        product_name = (options.get("product_name") or "").strip()
        dry_run = options.get("dry_run")

        qs = (
            StockTransfer.objects.filter(status=StockTransfer.Status.ACCEPTED)
            .select_related(
                "product",
                "customer_branch",
                "currency",
                "source_stock",
                "source_stock__purchase_item",
                "source_stock__purchase_item__unit",
                "target_stock",
                "target_stock__purchase_item",
                "target_stock__purchase_item__product",
                "target_stock__purchase_item__purchase",
                "created_by",
                "accepted_by",
            )
            .order_by("id")
        )
        if shop_id:
            qs = qs.filter(customer_branch_id=shop_id)
        if product_name:
            qs = qs.filter(product__name__icontains=product_name)

        helper = StockTransferViewSet()
        repaired = 0
        skipped = 0

        for transfer in qs:
            target = transfer.target_stock
            reason = self._needs_repair(helper, transfer, target)
            if not reason:
                skipped += 1
                continue

            self.stdout.write(
                f"Transfer #{transfer.id} ({transfer.product.name!r} -> "
                f"{transfer.customer_branch.name}): {reason}"
            )
            if dry_run:
                repaired += 1
                continue

            with transaction.atomic():
                self._repair_transfer(helper, transfer)

            repaired += 1
            self.stdout.write(self.style.SUCCESS(f"  repaired transfer #{transfer.id}"))

        self.stdout.write(
            self.style.NOTICE(
                f"Done. repaired={repaired} already_ok={skipped} dry_run={dry_run}"
            )
        )

    def _needs_repair(self, helper, transfer, target):
        if target is None or target.is_deleted:
            return "missing or deleted target_stock"
        if int(target.quantity or 0) <= 0:
            return None
        if target.shop_id != transfer.customer_branch_id:
            return "target_stock shop mismatch"
        pi = target.purchase_item
        if not helper._purchase_item_is_listable(pi):
            return "purchase_item not listable on Stock page"
        if transfer.product_id and pi.product_id:
            src_name = str(transfer.product.name or "").strip().casefold()
            dest_name = str(pi.product.name or "").strip().casefold()
            if src_name and dest_name and src_name != dest_name:
                return (
                    f"destination product name {pi.product.name!r} "
                    f"!= transfer product {transfer.product.name!r}"
                )
        return None

    def _repair_transfer(self, helper, transfer):
        user = transfer.accepted_by or transfer.created_by
        destination_product = helper._resolve_destination_product(transfer, user=user)
        transfer_currency = resolve_shop_currency(
            transfer.customer_branch_id,
            transfer.currency or (transfer.source_stock.currency if transfer.source_stock else None),
            user=user,
            create=True,
        )
        transfer_unit = helper._resolve_destination_unit(
            transfer.customer_branch_id,
            transfer.source_stock.unit if transfer.source_stock else None,
            user=user,
        )
        source_stock = transfer.source_stock
        transfer_buy_price = (
            transfer.sale_price
            if transfer.sale_price is not None
            else (
                (source_stock.sale_price or source_stock.retail_price or 0)
                if source_stock
                else 0
            )
        )

        target = transfer.target_stock
        if target is None or target.is_deleted or target.shop_id != transfer.customer_branch_id:
            target = helper._find_target_stock_for_transfer(
                transfer,
                transfer.customer_branch_id,
                transfer_currency.id if transfer_currency else transfer.currency_id,
            )
            if not target:
                target = Stock.objects.create(
                    shop_id=transfer.customer_branch_id,
                    purchase_item=None,
                    quantity=int(transfer.transfer_quantity or 0),
                    sale_price=(
                        transfer.sale_price
                        if transfer.sale_price is not None
                        else (source_stock.sale_price if source_stock else 0)
                    ),
                    average_buy_price=Decimal(
                        str(
                            transfer.sale_price
                            if transfer.sale_price is not None
                            else (source_stock.average_buy_price if source_stock else 0)
                            or 0
                        )
                    ),
                    wholesale_price=helper._transfer_wholesale_price(transfer, source_stock),
                    retail_price=helper._transfer_retail_price(transfer, source_stock),
                    created_by=user,
                )
            transfer.target_stock = target

        # If qty sits on a wrong-named product stock, move it onto the correct product row.
        pi = target.purchase_item
        if (
            helper._purchase_item_is_listable(pi)
            and destination_product
            and pi.product_id != destination_product.id
        ):
            correct = (
                Stock.objects.select_for_update()
                .filter(
                    shop_id=transfer.customer_branch_id,
                    is_deleted=False,
                    purchase_item__product_id=destination_product.id,
                    purchase_item__isnull=False,
                    purchase_item__is_deleted=False,
                    purchase_item__purchase__is_deleted=False,
                )
                .order_by("-quantity", "id")
                .first()
            )
            move_qty = int(transfer.transfer_quantity or 0)
            if correct and correct.id != target.id:
                correct.quantity = int(correct.quantity or 0) + move_qty
                correct.save(update_fields=["quantity", "updated_at"])
                target.quantity = max(0, int(target.quantity or 0) - move_qty)
                target.save(update_fields=["quantity", "updated_at"])
                target = correct
                transfer.target_stock = target
            else:
                pi.product = destination_product
                pi.save(update_fields=["product", "updated_at"])

        target = helper._ensure_target_stock_listable(
            target,
            transfer,
            destination_product,
            transfer_currency,
            transfer_unit,
            transfer_buy_price,
            source_stock,
            user,
        )
        transfer.target_stock = target
        transfer.save(update_fields=["target_stock", "updated_at"])
