"""
One-off data fix (2026-09-05): the author default margin moved from 25% to
30% (Author.default_my_keep_percent's model default was already changed in
migration 0040 — that only affects newly-created authors). This command:

  1. Sets default_my_keep_percent = 30.00 on every existing Author row.
  2. Recalculates every existing "direct-split" SaleItem (no BookstoreListing
     attached) whose snapshotted my_keep_percent is exactly 25.00 — i.e. one
     that was computed off the old default — to 30% instead, and refreshes
     the parent Sale's total_profit / total_author_payout to match.

SaleItems governed by a BookstoreListing (external/internal bookstore
consignment sales) are untouched: their payee_cut_percent is independent of
Author.default_my_keep_percent and wasn't affected by the old default either.
Likewise a SaleItem at some OTHER percent (30%, 50%, ...) is left alone —
only ones still showing the stale 25% get corrected.

This is a stopgap ("backdating" the blanket 30% onto existing records) until
real per-author negotiated percentages are set individually going forward.

Usage:
    python manage.py backfill_author_keep_percent --dry-run   # preview only
    python manage.py backfill_author_keep_percent             # commit
"""

from decimal import ROUND_HALF_UP, Decimal

from django.core.management.base import BaseCommand
from django.db import transaction
from django.db.models import Sum

from catalog_app.models import Author
from inventory.models import Sale, SaleItem

OLD_KEEP_PERCENT = Decimal("25.00")
NEW_KEEP_PERCENT = Decimal("30.00")
_TWO = Decimal("0.01")


class Command(BaseCommand):
    help = (
        "Set Author.default_my_keep_percent to 30% for every author, and recalculate "
        "existing direct-split SaleItems still snapshotted at the old 25% to match."
    )

    def add_arguments(self, parser):
        parser.add_argument(
            "--dry-run", action="store_true",
            help="Print what would change without saving anything.",
        )

    def handle(self, *args, **options):
        dry_run = options["dry_run"]

        authors = list(Author.objects.all())
        self.stdout.write(f"Authors to set to {NEW_KEEP_PERCENT}%: {len(authors)}")
        for author in authors:
            if author.default_my_keep_percent != NEW_KEEP_PERCENT:
                self.stdout.write(
                    f"  {author.name} (id={author.pk}): "
                    f"{author.default_my_keep_percent}% -> {NEW_KEEP_PERCENT}%"
                )

        items = list(
            SaleItem.objects
            .filter(bookstore_listing__isnull=True, my_keep_percent=OLD_KEEP_PERCENT)
            .select_related("sale", "book")
        )
        self.stdout.write(f"\nDirect-split SaleItems at {OLD_KEEP_PERCENT}% to recalculate: {len(items)}")

        affected_sale_ids = set()
        with transaction.atomic():
            if not dry_run:
                Author.objects.update(default_my_keep_percent=NEW_KEEP_PERCENT)

            for item in items:
                new_profit = (item.net_amount * NEW_KEEP_PERCENT / Decimal("100")).quantize(_TWO, ROUND_HALF_UP)
                new_payout = (item.net_amount - new_profit).quantize(_TWO)
                self.stdout.write(
                    f"  SaleItem {item.pk} | {item.sale.invoice_number} | {item.book.title} | "
                    f"my_profit_amount {item.my_profit_amount} -> {new_profit}, "
                    f"author_payout_amount {item.author_payout_amount} -> {new_payout}"
                )
                if not dry_run:
                    item.my_keep_percent = NEW_KEEP_PERCENT
                    item.author_pay_percent = Decimal("100") - NEW_KEEP_PERCENT
                    item.my_profit_amount = new_profit
                    item.author_payout_amount = new_payout
                    item.save(update_fields=[
                        "my_keep_percent", "author_pay_percent",
                        "my_profit_amount", "author_payout_amount",
                    ])
                    affected_sale_ids.add(item.sale_id)

            if not dry_run:
                for sale in Sale.objects.filter(pk__in=affected_sale_ids):
                    totals = sale.items.aggregate(
                        total_profit=Sum("my_profit_amount"),
                        total_payout=Sum("author_payout_amount"),
                    )
                    sale.total_profit = totals["total_profit"] or Decimal("0")
                    sale.total_author_payout = totals["total_payout"] or Decimal("0")
                    sale.save(update_fields=["total_profit", "total_author_payout"])

            if dry_run:
                transaction.set_rollback(True)

        if dry_run:
            self.stdout.write(self.style.WARNING("\nDRY RUN — nothing was saved. Re-run without --dry-run to commit."))
        else:
            self.stdout.write(self.style.SUCCESS(
                f"\nDone. {len(authors)} authors set to {NEW_KEEP_PERCENT}%, "
                f"{len(items)} sale items recalculated, {len(affected_sale_ids)} sales' totals refreshed."
            ))
