from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.utils import timezone
from decimal import Decimal
from datetime import timedelta
import random

from shop_management.models.data.shop import Shop
from shop_management.models.data.utils import Unit, Currency
from shop_management.models.data.product import Category, Product
from shop_management.models.data.customer import Customer
from shop_management.models.data.supplier import Supplier
from shop_management.models.data.employee import Employee
from shop_management.models.data.expense import ExpenseCategory, Expense
from shop_management.models.data.advance import Advance
from shop_management.models.data.payroll import Payroll
from shop_management.models.data.purchase import Purchase, PurchaseItem
from shop_management.models.data.purchase_payment import PurchasePayment
from shop_management.models.data.stock import Stock
from shop_management.models.data.sale import Sale, SaleItem
from shop_management.models.data.sale_payment import SalePayment
from shop_management.models.data.sale_return import SaleReturn, SaleReturnItem
from shop_management.models.data.purchase_return import PurchaseReturn, PurchaseReturnItem
from shop_management.models.data.customer_balance_payment import CustomerBalancePayment

User = get_user_model()


class Command(BaseCommand):
    help = 'Seed database with 50 records for each model'
    
    def clear_existing_data(self):
        self.stdout.write('Clearing existing data...')
        
        # Clear in reverse dependency order
        CustomerBalancePayment.objects.all().delete()
        PurchaseReturnItem.objects.all().delete()
        PurchaseReturn.objects.all().delete()
        SaleReturnItem.objects.all().delete()
        SaleReturn.objects.all().delete()
        SalePayment.objects.all().delete()
        SaleItem.objects.all().delete()
        Sale.objects.all().delete()
        Stock.objects.all().delete()
        PurchasePayment.objects.all().delete()
        PurchaseItem.objects.all().delete()
        Purchase.objects.all().delete()
        Payroll.objects.all().delete()
        Advance.objects.all().delete()
        Expense.objects.all().delete()
        ExpenseCategory.objects.all().delete()
        Employee.objects.all().delete()
        Supplier.objects.all().delete()
        Customer.objects.all().delete()
        Product.objects.all().delete()
        Category.objects.all().delete()
        Unit.objects.all().delete()
        Currency.objects.all().delete()
        Shop.objects.all().delete()
        User.objects.filter(is_superuser=False).delete()  # Keep superusers
        
        self.stdout.write(self.style.SUCCESS('Cleared existing data'))

    def handle(self, *args, **kwargs):
        self.stdout.write('Starting data seeding...')
        
        # Clear existing data first
        self.clear_existing_data()

        # Create users
        users = self.create_users()
        
        # Create shops
        shops = self.create_shops(users)
        
        # Create currencies and units
        currencies = self.create_currencies(shops)
        units = self.create_units(shops)
        
        # Create categories
        categories = self.create_categories(shops)
        
        # Create products
        products = self.create_products(shops, categories)
        
        # Create customers
        customers = self.create_customers(shops, currencies)
        
        # Create suppliers
        suppliers = self.create_suppliers(shops)
        
        # Create employees
        employees = self.create_employees(shops)
        
        # Create expense categories
        expense_categories = self.create_expense_categories()
        
        # Create expenses
        self.create_expenses(expense_categories, currencies)
        
        # Create advances
        self.create_advances(employees, currencies)
        
        # Create payrolls
        self.create_payrolls(shops, employees, currencies)
        
        # Create purchases
        purchases = self.create_purchases(shops, suppliers, currencies)
        
        # Create purchase items
        purchase_items = self.create_purchase_items(purchases, products, units)
        
        # Create purchase payments
        self.create_purchase_payments(purchases, currencies)
        
        # Create stocks
        self.create_stocks(shops, purchase_items)
        
        # Create sales
        sales = self.create_sales(shops, customers, currencies)
        
        # Create sale items
        sale_items = self.create_sale_items(sales, products, units)
        
        # Create sale payments
        self.create_sale_payments(sales, currencies)
        
        # Create sale returns
        sale_returns = self.create_sale_returns(shops, sales)
        
        # Create sale return items
        self.create_sale_return_items(sale_returns, sale_items)
        
        # Create purchase returns
        purchase_returns = self.create_purchase_returns(shops, purchases)
        
        # Create purchase return items
        self.create_purchase_return_items(purchase_returns, purchase_items)
        
        # Create customer balance payments
        self.create_customer_balance_payments(customers, currencies)

        self.stdout.write(self.style.SUCCESS('Successfully seeded all data!'))

    def create_users(self):
        self.stdout.write('Creating users...')
        users = []
        for i in range(50):
            user = User.objects.create_user(
                username=f'user{i+1}',
                email=f'user{i+1}@example.com',
                password='password123',
                first_name=f'First{i+1}',
                last_name=f'Last{i+1}',
                phone_number=f'+93700000{i+1:03d}',
                is_seller=random.choice([True, False])
            )
            users.append(user)
        self.stdout.write(self.style.SUCCESS(f'Created {len(users)} users'))
        return users

    def create_shops(self, users):
        self.stdout.write('Creating shops...')
        shops = []
        for i in range(50):
            shop = Shop.objects.create(
                owner=random.choice(users),
                name=f'Shop {i+1}',
                description=f'Description for shop {i+1}'
            )
            shops.append(shop)
        self.stdout.write(self.style.SUCCESS(f'Created {len(shops)} shops'))
        return shops

    def create_currencies(self, shops):
        self.stdout.write('Creating currencies...')
        currencies = []
        currency_names = ['AFN', 'USD', 'EUR', 'PKR', 'INR']
        for i in range(50):
            currency = Currency.objects.create(
                title=currency_names[i % len(currency_names)] + f'-{i+1}',
                description=f'Currency description {i+1}',
                shop=random.choice(shops)
            )
            currencies.append(currency)
        self.stdout.write(self.style.SUCCESS(f'Created {len(currencies)} currencies'))
        return currencies

    def create_units(self, shops):
        self.stdout.write('Creating units...')
        units = []
        unit_names = ['Piece', 'Box', 'Kg', 'Liter', 'Meter']
        for i in range(50):
            unit = Unit.objects.create(
                title=unit_names[i % len(unit_names)] + f'-{i+1}',
                description=f'Unit description {i+1}',
                shop=random.choice(shops)
            )
            units.append(unit)
        self.stdout.write(self.style.SUCCESS(f'Created {len(units)} units'))
        return units

    def create_categories(self, shops):
        self.stdout.write('Creating categories...')
        categories = []
        for i in range(50):
            category = Category.objects.create(
                shop=random.choice(shops),
                name=f'Category {i+1}',
                description=f'Category description {i+1}'
            )
            categories.append(category)
        self.stdout.write(self.style.SUCCESS(f'Created {len(categories)} categories'))
        return categories

    def create_products(self, shops, categories):
        self.stdout.write('Creating products...')
        products = []
        for i in range(50):
            product = Product.objects.create(
                shop=random.choice(shops),
                category=random.choice(categories),
                name=f'Product {i+1}',
                description=f'Product description {i+1}',
                pack=f'{random.randint(1, 10)}x{random.randint(1, 10)}',
                raf=f'RAF-{i+1}',
                carton=random.randint(1, 20)
            )
            products.append(product)
        self.stdout.write(self.style.SUCCESS(f'Created {len(products)} products'))
        return products

    def create_customers(self, shops, currencies):
        self.stdout.write('Creating customers...')
        customers = []
        for i in range(50):
            customer = Customer.objects.create(
                shop=random.choice(shops),
                name=f'Customer {i+1}',
                email=f'customer{i+1}@example.com',
                contact=f'+93700{i+1:06d}',
                address=f'Address {i+1}',
                opening_balance=Decimal(random.randint(0, 50000)),
                opening_balance_currency=random.choice(currencies)
            )
            customers.append(customer)
        self.stdout.write(self.style.SUCCESS(f'Created {len(customers)} customers'))
        return customers

    def create_suppliers(self, shops):
        self.stdout.write('Creating suppliers...')
        suppliers = []
        for i in range(50):
            supplier = Supplier.objects.create(
                shop=random.choice(shops),
                name=f'Supplier {i+1}',
                email=f'supplier{i+1}@example.com',
                contact=f'+93800{i+1:06d}',
                address=f'Supplier Address {i+1}'
            )
            suppliers.append(supplier)
        self.stdout.write(self.style.SUCCESS(f'Created {len(suppliers)} suppliers'))
        return suppliers

    def create_employees(self, shops):
        self.stdout.write('Creating employees...')
        employees = []
        for i in range(50):
            employee = Employee.objects.create(
                shop=random.choice(shops),
                name=f'Employee {i+1}',
                email=f'employee{i+1}@example.com',
                contact=f'+93900{i+1:06d}',
                address=f'Employee Address {i+1}',
                salary=Decimal(random.randint(10000, 50000)),
                age=random.randint(20, 60),
                contract_date=timezone.now().date() - timedelta(days=random.randint(0, 365)),
                contract_durations=f'{random.randint(1, 5)} years'
            )
            employees.append(employee)
        self.stdout.write(self.style.SUCCESS(f'Created {len(employees)} employees'))
        return employees

    def create_expense_categories(self):
        self.stdout.write('Creating expense categories...')
        categories = []
        category_names = ['Rent', 'Utilities', 'Salaries', 'Marketing', 'Maintenance']
        for i in range(50):
            category = ExpenseCategory.objects.create(
                name=category_names[i % len(category_names)] + f' {i+1}',
                description=f'Expense category description {i+1}'
            )
            categories.append(category)
        self.stdout.write(self.style.SUCCESS(f'Created {len(categories)} expense categories'))
        return categories

    def create_expenses(self, expense_categories, currencies):
        self.stdout.write('Creating expenses...')
        for i in range(50):
            Expense.objects.create(
                category=random.choice(expense_categories),
                expense_by=f'Person {i+1}',
                amount=Decimal(random.randint(100, 10000)),
                currency=random.choice(currencies),
                payment_date=timezone.now() - timedelta(days=random.randint(0, 365)),
                notes=f'Expense notes {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 expenses'))

    def create_advances(self, employees, currencies):
        self.stdout.write('Creating advances...')
        for i in range(50):
            Advance.objects.create(
                employee=random.choice(employees),
                amount=Decimal(random.randint(1000, 10000)),
                currency=random.choice(currencies),
                year=str(random.randint(2020, 2025)),
                month=str(random.randint(1, 12)),
                payment_date=timezone.now() - timedelta(days=random.randint(0, 365)),
                notes=f'Advance notes {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 advances'))

    def create_payrolls(self, shops, employees, currencies):
        self.stdout.write('Creating payrolls...')
        for i in range(50):
            Payroll.objects.create(
                shop=random.choice(shops),
                employee=random.choice(employees),
                amount=Decimal(random.randint(5000, 30000)),
                currency=random.choice(currencies),
                year=str(random.randint(2020, 2025)),
                month=str(random.randint(1, 12)),
                payment_date=timezone.now() - timedelta(days=random.randint(0, 365)),
                notes=f'Payroll notes {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 payrolls'))

    def create_purchases(self, shops, suppliers, currencies):
        self.stdout.write('Creating purchases...')
        purchases = []
        for i in range(50):
            purchase = Purchase.objects.create(
                shop=random.choice(shops),
                supplier=random.choice(suppliers),
                currency=random.choice(currencies),
                purchase_date=timezone.now().date() - timedelta(days=random.randint(0, 365)),
                discount=Decimal(random.randint(0, 1000)),
                received_amount=Decimal(random.randint(0, 50000)),
                status=random.choice([1, 2])
            )
            purchases.append(purchase)
        self.stdout.write(self.style.SUCCESS(f'Created {len(purchases)} purchases'))
        return purchases

    def create_purchase_items(self, purchases, products, units):
        self.stdout.write('Creating purchase items...')
        items = []
        for i in range(50):
            item = PurchaseItem.objects.create(
                purchase=random.choice(purchases),
                product=random.choice(products),
                unit=random.choice(units),
                quantity=random.randint(1, 100),
                buy_price=Decimal(random.randint(10, 1000)),
                sale_price=Decimal(random.randint(20, 1500)),
                expire_date=timezone.now().date() + timedelta(days=random.randint(30, 730))
            )
            items.append(item)
        self.stdout.write(self.style.SUCCESS(f'Created {len(items)} purchase items'))
        return items

    def create_purchase_payments(self, purchases, currencies):
        self.stdout.write('Creating purchase payments...')
        for i in range(50):
            PurchasePayment.objects.create(
                purchase=random.choice(purchases),
                currency=random.choice(currencies),
                amount=Decimal(random.randint(1000, 20000)),
                payment_date=timezone.now() - timedelta(days=random.randint(0, 365)),
                notes=f'Purchase payment notes {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 purchase payments'))

    def create_stocks(self, shops, purchase_items):
        self.stdout.write('Creating stocks...')
        for i in range(50):
            Stock.objects.create(
                shop=random.choice(shops),
                purchase_item=random.choice(purchase_items),
                quantity=random.randint(0, 500),
                sale_price=Decimal(random.randint(50, 2000)),
                comments=f'Stock comments {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 stocks'))

    def create_sales(self, shops, customers, currencies):
        self.stdout.write('Creating sales...')
        sales = []
        for i in range(50):
            sale = Sale.objects.create(
                shop=random.choice(shops),
                customer=random.choice(customers),
                sale_date=timezone.now().date() - timedelta(days=random.randint(0, 365)),
                discount=Decimal(random.randint(0, 500)),
                status=random.choice([1, 2]),
                currency=random.choice(currencies),
                received_amount=Decimal(random.randint(0, 30000)),
                notes=f'Sale notes {i+1}'
            )
            sales.append(sale)
        self.stdout.write(self.style.SUCCESS(f'Created {len(sales)} sales'))
        return sales

    def create_sale_items(self, sales, products, units):
        self.stdout.write('Creating sale items...')
        items = []
        for i in range(50):
            item = SaleItem.objects.create(
                sale=random.choice(sales),
                product=random.choice(products),
                quantity=random.randint(1, 50),
                unit=random.choice(units),
                sale_price=Decimal(random.randint(50, 2000))
            )
            items.append(item)
        self.stdout.write(self.style.SUCCESS(f'Created {len(items)} sale items'))
        return items

    def create_sale_payments(self, sales, currencies):
        self.stdout.write('Creating sale payments...')
        for i in range(50):
            SalePayment.objects.create(
                sale=random.choice(sales),
                currency=random.choice(currencies),
                amount=Decimal(random.randint(500, 15000)),
                payment_date=timezone.now() - timedelta(days=random.randint(0, 365)),
                notes=f'Sale payment notes {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 sale payments'))

    def create_sale_returns(self, shops, sales):
        self.stdout.write('Creating sale returns...')
        returns = []
        for i in range(50):
            sale_return = SaleReturn.objects.create(
                shop=random.choice(shops),
                sale=random.choice(sales),
                reason=f'Return reason {i+1}',
                total_refound_amount=Decimal(random.randint(100, 5000))
            )
            returns.append(sale_return)
        self.stdout.write(self.style.SUCCESS(f'Created {len(returns)} sale returns'))
        return returns

    def create_sale_return_items(self, sale_returns, sale_items):
        self.stdout.write('Creating sale return items...')
        for i in range(50):
            SaleReturnItem.objects.create(
                sale_return=random.choice(sale_returns),
                sale_item=random.choice(sale_items),
                return_quantity=random.randint(1, 10),
                refund_amount=Decimal(random.randint(50, 1000))
            )
        self.stdout.write(self.style.SUCCESS('Created 50 sale return items'))

    def create_purchase_returns(self, shops, purchases):
        self.stdout.write('Creating purchase returns...')
        returns = []
        for i in range(50):
            purchase_return = PurchaseReturn.objects.create(
                shop=random.choice(shops),
                purchase=random.choice(purchases),
                reason=f'Purchase return reason {i+1}'
            )
            returns.append(purchase_return)
        self.stdout.write(self.style.SUCCESS(f'Created {len(returns)} purchase returns'))
        return returns

    def create_purchase_return_items(self, purchase_returns, purchase_items):
        self.stdout.write('Creating purchase return items...')
        created_combinations = set()
        
        for i in range(50):
            # Find a unique combination
            attempts = 0
            while attempts < 100:  # Prevent infinite loop
                purchase_return = random.choice(purchase_returns)
                purchase_item = random.choice(purchase_items)
                combination = (purchase_return.id, purchase_item.id)
                
                if combination not in created_combinations:
                    created_combinations.add(combination)
                    break
                attempts += 1
            
            if attempts >= 100:
                continue  # Skip if we can't find a unique combination
            
            # Ensure return quantity doesn't exceed purchased quantity
            max_return_qty = min(purchase_item.quantity, 10)
            return_quantity = random.randint(1, max_return_qty) if max_return_qty > 0 else 1
            
            PurchaseReturnItem.objects.create(
                purchase_return=purchase_return,
                purchase_item=purchase_item,
                return_quantity=return_quantity,
                refund_amount=Decimal(random.randint(50, 1000))
            )
        self.stdout.write(self.style.SUCCESS('Created purchase return items'))

    def create_customer_balance_payments(self, customers, currencies):
        self.stdout.write('Creating customer balance payments...')
        for i in range(50):
            CustomerBalancePayment.objects.create(
                customer=random.choice(customers),
                amount=Decimal(random.randint(500, 10000)),
                currency=random.choice(currencies),
                payment_date=timezone.now() - timedelta(days=random.randint(0, 365)),
                notes=f'Balance payment notes {i+1}'
            )
        self.stdout.write(self.style.SUCCESS('Created 50 customer balance payments'))
