from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.utils import timezone
from datetime import timedelta
from decimal import Decimal
import random

from cashbook.models import (
    Business,
    Account,
    Category,
    Transaction,
    Contact,
    SaleItem,
)
from cashbook.services import (
    record_income,
    record_expense,
    record_transfer,
    get_or_create_debt_payment_category,
    get_or_create_payable_payment_category,
)


class Command(BaseCommand):
    help = "Seed demo data across all cashbook models (idempotent)."

    def handle(self, *args, **kwargs):
        User = get_user_model()

        # 1) User and Business
        user, _ = User.objects.get_or_create(
            username="owner",
            defaults={"is_staff": True, "is_superuser": True, "email": "owner@example.com"},
        )
        # Always ensure password works for demo logins
        user.set_password("owner")
        user.save(update_fields=["password"])

        biz, _ = Business.objects.get_or_create(
            owner=user,
            name="Kasa Demo",
            defaults={"currency": "XOF", "language": "en"},
        )

        # 2) Accounts (idempotent)
        cash, _ = Account.objects.get_or_create(
            business=biz, name="Cashbox", defaults={"type": Account.CASH, "opening_balance": Decimal("50000")}
        )
        wave, _ = Account.objects.get_or_create(
            business=biz, name="Wave", defaults={"type": Account.MOBILE, "opening_balance": Decimal("25000")}
        )
        bank, _ = Account.objects.get_or_create(
            business=biz, name="Bank", defaults={"type": Account.BANK, "opening_balance": Decimal("150000")}
        )

        # 3) Categories (idempotent)
        sales, _ = Category.objects.get_or_create(
            business=biz, name="Sales", defaults={"type": Category.INCOME, "status": Category.ACTIVE}
        )
        services, _ = Category.objects.get_or_create(
            business=biz, name="Services", defaults={"type": Category.INCOME, "status": Category.ACTIVE}
        )
        stock, _ = Category.objects.get_or_create(
            business=biz, name="Stock Purchase", defaults={"type": Category.EXPENSE, "status": Category.ACTIVE}
        )
        transport, _ = Category.objects.get_or_create(
            business=biz, name="Transport", defaults={"type": Category.EXPENSE, "status": Category.ACTIVE}
        )
        utilities, _ = Category.objects.get_or_create(
            business=biz, name="Utilities", defaults={"type": Category.EXPENSE, "status": Category.ACTIVE}
        )
        debt_payment = get_or_create_debt_payment_category(biz)
        payable_payment = get_or_create_payable_payment_category(biz)

        # 4) Contacts (idempotent)
        cust1, _ = Contact.objects.get_or_create(business=biz, name="Alice Customer", defaults={"ctype": Contact.CUSTOMER, "phone": "+22501020304"})
        cust2, _ = Contact.objects.get_or_create(business=biz, name="Ben Client", defaults={"ctype": Contact.CUSTOMER, "phone": "+221770000000"})
        supp1, _ = Contact.objects.get_or_create(business=biz, name="Bob Supplier", defaults={"ctype": Contact.SUPPLIER, "phone": "+233240000000"})
        supp2, _ = Contact.objects.get_or_create(business=biz, name="Dora Supplier", defaults={"ctype": Contact.SUPPLIER})

        # 5) Transactions
        # Create a small batch only if not present to avoid duplication spam
        if not Transaction.objects.filter(business=biz).exists():
            rng = random.Random(42)
            today = timezone.localdate()
            accounts = [cash, wave, bank]

            # a) Recent sales (some on credit) with sale items
            for i in range(10):
                tx_date = today - timedelta(days=10 - i)
                account = rng.choice(accounts)
                category = rng.choice([sales, services])
                customer = rng.choice([cust1, cust2, None])
                # Amount between 3,000 and 20,000
                amount = Decimal(rng.randrange(3000, 20001))
                is_credit = (i % 3 == 0)  # 1/3 of sales are credit
                due_date = (tx_date + timedelta(days=rng.choice([7, 14, 30]))) if is_credit else None

                tx = record_income(
                    business=biz,
                    user=user,
                    date=tx_date,
                    account=account,
                    category=category,
                    amount=amount,
                    currency=biz.currency,
                    description=f"{category.name} #{i+1}",
                    contact=customer,
                    is_credit=is_credit,
                    due_date=due_date,
                )

                # Add 1-3 sale items that sum to total
                parts = rng.randint(1, 3)
                remaining = amount
                for p in range(parts):
                    if p == parts - 1:
                        part_amount = remaining
                    else:
                        # split remaining
                        part_amount = (remaining * Decimal(rng.uniform(0.2, 0.6))).quantize(Decimal("1."))
                        if part_amount <= 0:
                            part_amount = Decimal("1")
                    remaining -= part_amount
                    qty = Decimal(rng.choice([1, 1, 2, 3]))
                    price = (part_amount / qty).quantize(Decimal("1."))
                    SaleItem.objects.create(
                        transaction=tx,
                        name=f"Item {p+1}",
                        quantity=qty,
                        price=price,
                        amount=part_amount,
                    )

            # b) Expenses (some as credit purchases)
            for i in range(8):
                tx_date = today - timedelta(days=8 - i)
                account = rng.choice(accounts)
                category = rng.choice([stock, transport, utilities])
                supplier = rng.choice([supp1, supp2, None])
                amount = Decimal(rng.randrange(1000, 12001))
                is_credit = (i % 4 == 0)  # some expenses on credit
                due_date = (tx_date + timedelta(days=rng.choice([7, 14, 30]))) if is_credit else None

                record_expense(
                    business=biz,
                    user=user,
                    date=tx_date,
                    account=account,
                    category=category,
                    amount=amount,
                    currency=biz.currency,
                    description=f"{category.name} expense #{i+1}",
                    contact=supplier,
                    is_credit=is_credit,
                    due_date=due_date,
                )

            # c) A couple of transfers
            record_transfer(
                business=biz,
                user=user,
                date=today - timedelta(days=3),
                from_account=cash,
                to_account=bank,
                amount=Decimal("20000"),
                currency=biz.currency,
                description="Deposit to bank",
            )
            record_transfer(
                business=biz,
                user=user,
                date=today - timedelta(days=1),
                from_account=bank,
                to_account=wave,
                amount=Decimal("15000"),
                currency=biz.currency,
                description="Top-up mobile money",
            )

            # d) Settle one customer receivable and one supplier payable
            #    using special categories so KPIs look realistic
            # Find one recent credit sale and one credit expense
            credit_sale = (
                Transaction.objects.filter(business=biz, ttype=Transaction.INCOME, is_credit=True, contact__isnull=False)
                .order_by("-date")
                .first()
            )
            if credit_sale:
                record_income(
                    business=biz,
                    user=user,
                    date=min(today, credit_sale.date + timedelta(days=7)),
                    account=cash,
                    category=debt_payment,
                    amount=credit_sale.amount / 2,  # partial settlement
                    currency=biz.currency,
                    description=f"Settlement from {credit_sale.contact.name}",
                    contact=credit_sale.contact,
                )
            credit_exp = (
                Transaction.objects.filter(business=biz, ttype=Transaction.EXPENSE, is_credit=True, contact__isnull=False)
                .order_by("-date")
                .first()
            )
            if credit_exp:
                record_expense(
                    business=biz,
                    user=user,
                    date=min(today, credit_exp.date + timedelta(days=5)),
                    account=cash,
                    category=payable_payment,
                    amount=credit_exp.amount / 2,
                    currency=biz.currency,
                    description=f"Payment to {credit_exp.contact.name}",
                    contact=credit_exp.contact,
                )

        self.stdout.write(self.style.SUCCESS("Seeded demo data. Login: owner / owner"))
