from __future__ import annotations

from decimal import Decimal

from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.utils import timezone

from orgs.models import Organization, UserProfile
from recycle_core.models import (
    MaterialCategory,
    Material,
    PriceList,
    PriceListItem,
    Customer,
    CustomerSite,
    PickupOrder,
    PickupItem,
    WeighTicket,
    WeighLine,
    ScrapListing,
    ScrapListingItem,
    ScrapBid,
)
from recycle_core.services.billing import generate_invoice_for_pickup


User = get_user_model()


class Command(BaseCommand):
    help = "Seed demo data for Ecoloop: org, materials, price list, customer, pickup, weigh ticket, invoice"

    def add_arguments(self, parser):
        parser.add_argument("--org", default="DEMO", help="Organization code/id/name to seed (default: DEMO)")
        parser.add_argument("--bidder-org", dest="bidder_org", default="REC1", help="Bidder org code/id/name (default: REC1)")

    def handle(self, *args, **options):
        now = timezone.now()

        def _resolve_org(ident: str, *, default_name: str) -> Organization:
            if ident and ident.isdigit():
                org = Organization.objects.filter(pk=int(ident)).first()
                if org:
                    return org
            org = (
                Organization.objects.filter(code=ident).first()
                or Organization.objects.filter(name=ident).first()
            )
            if org:
                return org
            # Create with defaults if not found
            return Organization.objects.create(code=ident, name=default_name, timezone="UTC", currency_code="THB")

        org_ident = options.get("org") or "DEMO"
        bidder_ident = options.get("bidder_org") or "REC1"

        org = _resolve_org(org_ident, default_name=("Ecoloop " + str(org_ident)))
        bidder_org = _resolve_org(bidder_ident, default_name="Recycler Co.")

        # Users
        manager = User.objects.filter(username="manager").first()
        if not manager:
            manager = User.objects.create_user(username="manager", email="manager@example.com", password="manager123")
        driver = User.objects.filter(username="driver").first()
        if not driver:
            driver = User.objects.create_user(username="driver", email="driver@example.com", password="driver123")
        buyer = User.objects.filter(username="buyer").first()
        if not buyer:
            buyer = User.objects.create_user(username="buyer", email="buyer@example.com", password="buyer123")

        # Ensure recycle_core user profiles and roles
        UserProfile.objects.get_or_create(user=manager, defaults={"organization": org, "role": UserProfile.ROLE_MANAGER})
        UserProfile.objects.get_or_create(user=driver, defaults={"organization": org, "role": UserProfile.ROLE_DRIVER})
        UserProfile.objects.get_or_create(user=buyer, defaults={"organization": bidder_org, "role": UserProfile.ROLE_MANAGER})

        # Materials and categories
        plastics, _ = MaterialCategory.objects.get_or_create(organization=org, name="Plastics")
        metals, _ = MaterialCategory.objects.get_or_create(organization=org, name="Metals")
        paper, _ = MaterialCategory.objects.get_or_create(organization=org, name="Paper")

        pet, _ = Material.objects.get_or_create(organization=org, category=plastics, name="PET", defaults={"default_unit": Material.UNIT_KG})
        hdpe, _ = Material.objects.get_or_create(organization=org, category=plastics, name="HDPE", defaults={"default_unit": Material.UNIT_KG})
        can, _ = Material.objects.get_or_create(organization=org, category=metals, name="Aluminum Can", defaults={"default_unit": Material.UNIT_KG})
        cardboard, _ = Material.objects.get_or_create(organization=org, category=paper, name="Cardboard", defaults={"default_unit": Material.UNIT_KG})

        # Price list
        pl, _ = PriceList.objects.get_or_create(
            organization=org,
            name="Standard",
            defaults={"currency_code": "THB"},
        )
        # Sell prices (invoice customer)
        PriceListItem.objects.get_or_create(price_list=pl, material=pet, unit=Material.UNIT_KG, direction=PriceListItem.DIRECTION_SELL, defaults={"unit_price": Decimal("5.00")})
        PriceListItem.objects.get_or_create(price_list=pl, material=hdpe, unit=Material.UNIT_KG, direction=PriceListItem.DIRECTION_SELL, defaults={"unit_price": Decimal("4.00")})
        PriceListItem.objects.get_or_create(price_list=pl, material=can, unit=Material.UNIT_KG, direction=PriceListItem.DIRECTION_SELL, defaults={"unit_price": Decimal("12.00")})
        PriceListItem.objects.get_or_create(price_list=pl, material=cardboard, unit=Material.UNIT_KG, direction=PriceListItem.DIRECTION_SELL, defaults={"unit_price": Decimal("2.00")})
        # Buy prices (pay customer)
        PriceListItem.objects.get_or_create(price_list=pl, material=pet, unit=Material.UNIT_KG, direction=PriceListItem.DIRECTION_BUY, defaults={"unit_price": Decimal("1.50")})
        PriceListItem.objects.get_or_create(price_list=pl, material=hdpe, unit=Material.UNIT_KG, direction=PriceListItem.DIRECTION_BUY, defaults={"unit_price": Decimal("1.20")})

        # Customer and site
        customer, _ = Customer.objects.get_or_create(
            organization=org,
            name="Acme Factory",
            defaults={
                "email": "ops@acme.example",
                "phone": "+66 000 0000",
                "billing_address": "123 Demo Rd, Bangkok",
                "price_list": pl,
            },
        )
        site, _ = CustomerSite.objects.get_or_create(
            customer=customer,
            name="Acme Plant #1",
            defaults={
                "address": "123 Demo Rd, Bangkok",
                "contact_name": "Somchai",
                "contact_phone": "+66 111 1111",
                "contact_email": "somchai@acme.example",
            },
        )

        pickup = PickupOrder.objects.create(
            organization=org,
            customer=customer,
            site=site,
            status=PickupOrder.STATUS_SCHEDULED,
            scheduled_at=now + timezone.timedelta(days=1),
            assigned_driver=driver,
            created_by=manager,
            notes="Demo pickup order",
        )
        PickupItem.objects.create(pickup=pickup, material=pet, estimated_qty=Decimal("100.0"), unit=Material.UNIT_KG)
        PickupItem.objects.create(pickup=pickup, material=can, estimated_qty=Decimal("50.0"), unit=Material.UNIT_KG)

        ticket = WeighTicket.objects.create(
            pickup=pickup,
            ticket_number=f"WT-{pickup.id}",
            gross_weight=Decimal("200.000"),
            tare_weight=Decimal("40.000"),
            net_weight=Decimal("160.000"),
            unit=Material.UNIT_KG,
            recorded_by=manager,
        )
        WeighLine.objects.create(ticket=ticket, material=pet, quantity=Decimal("110.000"), unit=Material.UNIT_KG)
        WeighLine.objects.create(ticket=ticket, material=can, quantity=Decimal("50.000"), unit=Material.UNIT_KG)

        pickup.status = PickupOrder.STATUS_WEIGHED
        pickup.save(update_fields=["status"])

        invoice = generate_invoice_for_pickup(pickup)

        # Create a demo scrap listing and a bid
        listing = ScrapListing.objects.create(
            organization=org,
            customer=customer,
            site=site,
            title="Monthly PET + Cans lot",
            description="Estimated quantities of PET and aluminum cans available",
            auction_type=ScrapListing.TYPE_OPEN,
            currency_code="THB",
            reserve_price=Decimal("500.00"),
            min_increment=Decimal("50.00"),
            status=ScrapListing.STATUS_OPEN,
            is_public=False,
            starts_at=now,
            created_by=manager,
        )
        ScrapListingItem.objects.create(listing=listing, material=pet, quantity_estimate=Decimal("100.0"), unit=Material.UNIT_KG)
        ScrapListingItem.objects.create(listing=listing, material=can, quantity_estimate=Decimal("50.0"), unit=Material.UNIT_KG)
        # Invite-only demo: invite bidder_org then place bid
        from recycle_core.models import ScrapListingInvite
        ScrapListingInvite.objects.get_or_create(listing=listing, invited_org=bidder_org, invited_user=buyer)
        ScrapBid.objects.create(listing=listing, bidder_org=bidder_org, bidder_user=buyer, price_total=Decimal("550.00"), message="Ready to collect within 48h")

        self.stdout.write(self.style.SUCCESS("Seeded Ecoloop demo data"))
        self.stdout.write(f"Organization: {org.name} ({org.code})")
        self.stdout.write(f"Customer: {customer.name}")
        self.stdout.write(f"Pickup: {pickup.id} status={pickup.status}")
        self.stdout.write(f"WeighTicket: {ticket.ticket_number}")
        self.stdout.write(f"Invoice: {invoice.id} total={invoice.total_amount} {invoice.currency_code}")
        self.stdout.write(f"Scrap Listing: {listing.id} status={listing.status}")
