#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Demo Stock Seeding Script for Inventory Service
Creates realistic stock batches with varied expiration dates for demo template tenants

This script runs as a Kubernetes init job inside the inventory-service container.
It populates the template tenants with stock data that will demonstrate inventory alerts.

Usage:
    python /app/scripts/demo/seed_demo_stock.py

Environment Variables Required:
    INVENTORY_DATABASE_URL - PostgreSQL connection string for inventory database
    DEMO_MODE - Set to 'production' for production seeding
    LOG_LEVEL - Logging level (default: INFO)
"""

import asyncio
import uuid
import sys
import os
import random
import json
from datetime import datetime, timezone, timedelta
from pathlib import Path
from decimal import Decimal

# Add app to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import select
import structlog

from app.models.inventory import Ingredient, Stock, StockMovement, StockMovementType

# Configure logging
structlog.configure(
    processors=[
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.dev.ConsoleRenderer()
    ]
)

logger = structlog.get_logger()

# Fixed Demo Tenant IDs (must match tenant service)
DEMO_TENANT_SAN_PABLO = uuid.UUID("a1b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6")
DEMO_TENANT_LA_ESPIGA = uuid.UUID("b2c3d4e5-f6a7-48b9-c0d1-e2f3a4b5c6d7")

# Base reference date for demo data (all relative dates calculated from this)
BASE_REFERENCE_DATE = datetime(2025, 1, 15, 12, 0, 0, tzinfo=timezone.utc)

# Load configuration from JSON
def load_stock_config():
    """Load stock configuration from JSON file"""
    config_file = Path(__file__).parent / "stock_lotes_es.json"

    if not config_file.exists():
        raise FileNotFoundError(f"Stock configuration file not found: {config_file}")

    logger.info("Loading stock configuration", file=str(config_file))

    with open(config_file, 'r', encoding='utf-8') as f:
        return json.load(f)

# Load configuration
STOCK_CONFIG = load_stock_config()
STORAGE_LOCATIONS = STOCK_CONFIG["stock_distribution"]["storage_locations"]
WAREHOUSE_ZONES = STOCK_CONFIG["stock_distribution"]["warehouse_zones"]
QUALITY_STATUSES = ["good", "damaged", "expired", "quarantined"]


def generate_batch_number(tenant_id: uuid.UUID, ingredient_sku: str, batch_index: int) -> str:
    """Generate a realistic batch number"""
    tenant_short = str(tenant_id).split('-')[0].upper()[:4]
    return f"LOTE-{tenant_short}-{ingredient_sku}-{batch_index:03d}"


def calculate_expiration_distribution():
    """
    Calculate expiration date distribution for realistic demo alerts

    Distribution:
    - 5% expired (already past expiration)
    - 10% expiring soon (< 3 days)
    - 15% moderate alert (3-7 days)
    - 30% short-term (7-30 days)
    - 40% long-term (30-90 days)
    """
    rand = random.random()

    if rand < 0.05:  # 5% expired
        return random.randint(-10, -1)
    elif rand < 0.15:  # 10% expiring soon
        return random.randint(1, 3)
    elif rand < 0.30:  # 15% moderate alert
        return random.randint(3, 7)
    elif rand < 0.60:  # 30% short-term
        return random.randint(7, 30)
    else:  # 40% long-term
        return random.randint(30, 90)


async def create_stock_batches_for_ingredient(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    ingredient: Ingredient,
    base_date: datetime
) -> list:
    """
    Create 1-2 stock batches for a single ingredient (optimized for demo performance)

    Args:
        db: Database session
        tenant_id: Tenant UUID
        ingredient: Ingredient model instance
        base_date: Base reference date for calculating expiration dates

    Returns:
        List of created Stock instances
    """
    stocks = []
    num_batches = random.randint(1, 2)  # Reduced from 3-5 for faster demo loading

    # Calculate target total stock for this ingredient
    # Use 40-80% of max_stock_level to allow for realistic variation
    # If max_stock_level is not set, use reorder_point * 3 as a reasonable target
    if ingredient.max_stock_level:
        target_total_stock = float(ingredient.max_stock_level) * random.uniform(0.4, 0.8)
    else:
        target_total_stock = float(ingredient.reorder_point or 50.0) * 3.0

    # Distribute total stock across batches
    batch_quantities = []
    remaining = target_total_stock
    for i in range(num_batches):
        if i == num_batches - 1:
            # Last batch gets whatever is remaining
            batch_quantities.append(remaining)
        else:
            # Earlier batches get a random portion of remaining
            portion = remaining * random.uniform(0.3, 0.7)
            batch_quantities.append(portion)
            remaining -= portion

    for i in range(num_batches):
        # Calculate expiration days offset
        days_offset = calculate_expiration_distribution()
        expiration_date = base_date + timedelta(days=days_offset)
        received_date = expiration_date - timedelta(days=ingredient.shelf_life_days or 30)

        # Determine if expired
        is_expired = days_offset < 0

        # Quality status based on expiration
        if is_expired:
            quality_status = random.choice(["expired", "quarantined"])
            is_available = False
        elif days_offset < 3:
            quality_status = random.choice(["good", "good", "good", "damaged"])  # Mostly good
            is_available = quality_status == "good"
        else:
            quality_status = "good"
            is_available = True

        # Use pre-calculated batch quantity
        current_quantity = round(batch_quantities[i], 2)

        # Reserve 0-30% of current quantity if available
        reserved_quantity = round(random.uniform(0.0, current_quantity * 0.3), 2) if is_available else 0.0
        available_quantity = current_quantity - reserved_quantity

        # Calculate costs with variation
        base_cost = float(ingredient.average_cost or Decimal("1.0"))
        unit_cost = Decimal(str(round(base_cost * random.uniform(0.9, 1.1), 2)))
        total_cost = unit_cost * Decimal(str(current_quantity))

        # Determine storage requirements
        requires_refrigeration = ingredient.is_perishable and ingredient.ingredient_category.value in ['dairy', 'eggs']
        requires_freezing = False  # Could be enhanced based on ingredient type

        stock = Stock(
            id=uuid.uuid4(),
            tenant_id=tenant_id,
            ingredient_id=ingredient.id,
            supplier_id=None,  # Could link to suppliers in future
            batch_number=generate_batch_number(tenant_id, ingredient.sku or f"SKU{i}", i + 1),
            lot_number=f"LOT-{random.randint(1000, 9999)}",
            supplier_batch_ref=f"SUP-{random.randint(10000, 99999)}",
            production_stage='raw_ingredient',
            current_quantity=current_quantity,
            reserved_quantity=reserved_quantity,
            available_quantity=available_quantity,
            received_date=received_date,
            expiration_date=expiration_date,
            best_before_date=expiration_date - timedelta(days=2) if ingredient.is_perishable else None,
            unit_cost=unit_cost,
            total_cost=total_cost,
            storage_location=random.choice(STORAGE_LOCATIONS),
            warehouse_zone=random.choice(["A", "B", "C", "D"]),
            shelf_position=f"{random.randint(1, 20)}-{random.choice(['A', 'B', 'C'])}",
            requires_refrigeration=requires_refrigeration,
            requires_freezing=requires_freezing,
            storage_temperature_min=2.0 if requires_refrigeration else None,
            storage_temperature_max=8.0 if requires_refrigeration else None,
            shelf_life_days=ingredient.shelf_life_days,
            is_available=is_available,
            is_expired=is_expired,
            quality_status=quality_status,
            created_at=received_date,
            updated_at=datetime.now(timezone.utc)
        )

        stocks.append(stock)

    return stocks


async def create_waste_movements_for_tenant(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    base_date: datetime
) -> list:
    """
    Create realistic waste stock movements for the past 30 days

    Args:
        db: Database session
        tenant_id: UUID of the tenant
        base_date: Base reference date for movement calculations

    Returns:
        List of created StockMovement instances
    """
    # Get all stock for this tenant (including expired)
    result = await db.execute(
        select(Stock, Ingredient).join(
            Ingredient, Stock.ingredient_id == Ingredient.id
        ).where(
            Stock.tenant_id == tenant_id
        )
    )
    stock_items = result.all()

    if not stock_items:
        return []

    movements = []
    waste_reasons = [
        ("spoilage", 0.40),  # 40% of waste is spoilage
        ("expired", 0.30),   # 30% is expiration
        ("damage", 0.20),    # 20% is damage
        ("contamination", 0.10)  # 10% is contamination
    ]

    # Create waste movements for expired stock
    for stock, ingredient in stock_items:
        if stock.is_expired and stock.current_quantity > 0:
            # Create waste movement for expired stock
            waste_quantity = stock.current_quantity
            movement_date = stock.expiration_date + timedelta(days=random.randint(1, 3))

            movement = StockMovement(
                id=uuid.uuid4(),
                tenant_id=tenant_id,
                ingredient_id=ingredient.id,
                stock_id=stock.id,
                movement_type=StockMovementType.WASTE,
                quantity=waste_quantity,
                unit_cost=stock.unit_cost,
                total_cost=stock.unit_cost * Decimal(str(waste_quantity)) if stock.unit_cost else None,
                reason_code="expired",
                notes=f"Lote {stock.batch_number} caducado - movimiento automático de desperdicio",
                reference_number=f"WASTE-EXP-{stock.batch_number}",
                movement_date=movement_date,
                created_at=movement_date,
                created_by=None  # System-generated
            )
            movements.append(movement)

    # Create additional random waste movements for the past 30 days
    # to show waste patterns from spoilage, damage, etc.
    num_waste_movements = random.randint(8, 15)  # 8-15 waste incidents in 30 days

    for i in range(num_waste_movements):
        # Select random non-expired stock
        available_stock = [(s, i) for s, i in stock_items if not s.is_expired and s.current_quantity > 5.0]
        if not available_stock:
            continue

        stock, ingredient = random.choice(available_stock)

        # Random date in the past 30 days
        days_ago = random.randint(1, 30)
        movement_date = base_date - timedelta(days=days_ago)

        # Random waste quantity (1-10% of current stock)
        waste_percentage = random.uniform(0.01, 0.10)
        waste_quantity = round(stock.current_quantity * waste_percentage, 2)

        # Select random waste reason
        reason, _ = random.choices(
            waste_reasons,
            weights=[w for _, w in waste_reasons]
        )[0]

        # Create waste movement
        movement = StockMovement(
            id=uuid.uuid4(),
            tenant_id=tenant_id,
            ingredient_id=ingredient.id,
            stock_id=stock.id,
            movement_type=StockMovementType.WASTE,
            quantity=waste_quantity,
            unit_cost=stock.unit_cost,
            total_cost=stock.unit_cost * Decimal(str(waste_quantity)) if stock.unit_cost else None,
            reason_code=reason,
            notes=f"Desperdicio de {ingredient.name} por {reason}",
            reference_number=f"WASTE-{reason.upper()}-{i+1:03d}",
            movement_date=movement_date,
            created_at=movement_date,
            created_by=None  # System-generated
        )
        movements.append(movement)

    return movements


async def create_purchase_movements_for_stock(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    base_date: datetime
) -> list:
    """
    Create PURCHASE movements for all stock batches

    Each stock batch should have a corresponding PURCHASE movement
    representing when it was received from the supplier.

    Args:
        db: Database session
        tenant_id: UUID of the tenant
        base_date: Base reference date for movement calculations

    Returns:
        List of created StockMovement instances
    """
    # Get all stock for this tenant
    result = await db.execute(
        select(Stock, Ingredient).join(
            Ingredient, Stock.ingredient_id == Ingredient.id
        ).where(
            Stock.tenant_id == tenant_id
        )
    )
    stock_items = result.all()

    if not stock_items:
        return []

    movements = []

    for stock, ingredient in stock_items:
        # Create PURCHASE movement for each stock batch
        # Movement date is the received date of the stock
        movement_date = stock.received_date

        movement = StockMovement(
            id=uuid.uuid4(),
            tenant_id=tenant_id,
            ingredient_id=ingredient.id,
            stock_id=stock.id,
            movement_type=StockMovementType.PURCHASE,
            quantity=stock.current_quantity + stock.reserved_quantity,  # Total received
            unit_cost=stock.unit_cost,
            total_cost=stock.total_cost,
            quantity_before=0.0,  # Was zero before purchase
            quantity_after=stock.current_quantity + stock.reserved_quantity,
            reference_number=f"PO-{movement_date.strftime('%Y%m')}-{random.randint(1000, 9999)}",
            supplier_id=stock.supplier_id,
            notes=f"Compra de {ingredient.name} - Lote {stock.batch_number}",
            movement_date=movement_date,
            created_at=movement_date,
            created_by=None  # System-generated
        )
        movements.append(movement)

    return movements


async def create_production_use_movements(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    base_date: datetime
) -> list:
    """
    Create realistic PRODUCTION_USE movements for the past 30 days

    Simulates ingredients being consumed in production runs.

    Args:
        db: Database session
        tenant_id: UUID of the tenant
        base_date: Base reference date for movement calculations

    Returns:
        List of created StockMovement instances
    """
    # Get all available stock for this tenant
    result = await db.execute(
        select(Stock, Ingredient).join(
            Ingredient, Stock.ingredient_id == Ingredient.id
        ).where(
            Stock.tenant_id == tenant_id,
            Stock.is_available == True,
            Stock.current_quantity > 10.0  # Only use stock with sufficient quantity
        )
    )
    stock_items = result.all()

    if not stock_items:
        return []

    movements = []

    # Create 15-25 production use movements spread over 30 days
    num_production_runs = random.randint(15, 25)

    production_types = [
        ("Pan Rústico", 20.0, 50.0),  # 20-50 kg flour
        ("Pan de Molde", 15.0, 40.0),
        ("Croissants", 10.0, 30.0),
        ("Baguettes", 25.0, 60.0),
        ("Bollería Variada", 12.0, 35.0),
        ("Pan Integral", 18.0, 45.0)
    ]

    for i in range(num_production_runs):
        # Select random stock item
        if not stock_items:
            break

        stock, ingredient = random.choice(stock_items)

        # Random date in the past 30 days
        days_ago = random.randint(1, 30)
        movement_date = base_date - timedelta(days=days_ago)

        # Random production type and quantity
        production_name, min_qty, max_qty = random.choice(production_types)

        # Production quantity (5-20% of current stock, within min/max range)
        use_percentage = random.uniform(0.05, 0.20)
        use_quantity = round(min(
            stock.current_quantity * use_percentage,
            random.uniform(min_qty, max_qty)
        ), 2)

        # Ensure we don't consume more than available
        if use_quantity > stock.available_quantity:
            use_quantity = round(stock.available_quantity * 0.5, 2)

        if use_quantity < 1.0:
            continue

        # Create production use movement
        movement = StockMovement(
            id=uuid.uuid4(),
            tenant_id=tenant_id,
            ingredient_id=ingredient.id,
            stock_id=stock.id,
            movement_type=StockMovementType.PRODUCTION_USE,
            quantity=use_quantity,
            unit_cost=stock.unit_cost,
            total_cost=stock.unit_cost * Decimal(str(use_quantity)) if stock.unit_cost else None,
            quantity_before=stock.current_quantity,
            quantity_after=stock.current_quantity - use_quantity,
            reference_number=f"PROD-{movement_date.strftime('%Y%m%d')}-{i+1:03d}",
            notes=f"Producción de {production_name} - Consumo de {ingredient.name}",
            movement_date=movement_date,
            created_at=movement_date,
            created_by=None  # System-generated
        )
        movements.append(movement)

        # Update stock quantity for realistic simulation (don't commit, just for calculation)
        stock.current_quantity -= use_quantity
        stock.available_quantity -= use_quantity

    return movements


async def create_adjustment_movements(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    base_date: datetime
) -> list:
    """
    Create inventory ADJUSTMENT movements

    Represents inventory counts and corrections.

    Args:
        db: Database session
        tenant_id: UUID of the tenant
        base_date: Base reference date for movement calculations

    Returns:
        List of created StockMovement instances
    """
    # Get all stock for this tenant
    result = await db.execute(
        select(Stock, Ingredient).join(
            Ingredient, Stock.ingredient_id == Ingredient.id
        ).where(
            Stock.tenant_id == tenant_id,
            Stock.current_quantity > 5.0
        )
    )
    stock_items = result.all()

    if not stock_items:
        return []

    movements = []

    adjustment_reasons = [
        ("inventory_count", "Conteo de inventario mensual"),
        ("correction", "Corrección de entrada incorrecta"),
        ("shrinkage", "Ajuste por merma natural"),
        ("reconciliation", "Reconciliación de stock")
    ]

    # Create 3-5 adjustment movements
    num_adjustments = random.randint(3, 5)

    for i in range(num_adjustments):
        if not stock_items:
            break

        stock, ingredient = random.choice(stock_items)

        # Random date in the past 30 days
        days_ago = random.randint(5, 30)
        movement_date = base_date - timedelta(days=days_ago)

        # Random adjustment (±5% of current stock)
        adjustment_percentage = random.uniform(-0.05, 0.05)
        adjustment_quantity = round(stock.current_quantity * adjustment_percentage, 2)

        if abs(adjustment_quantity) < 0.1:
            continue

        reason_code, reason_note = random.choice(adjustment_reasons)

        # Create adjustment movement
        movement = StockMovement(
            id=uuid.uuid4(),
            tenant_id=tenant_id,
            ingredient_id=ingredient.id,
            stock_id=stock.id,
            movement_type=StockMovementType.ADJUSTMENT,
            quantity=abs(adjustment_quantity),
            unit_cost=stock.unit_cost,
            total_cost=stock.unit_cost * Decimal(str(abs(adjustment_quantity))) if stock.unit_cost else None,
            quantity_before=stock.current_quantity,
            quantity_after=stock.current_quantity + adjustment_quantity,
            reference_number=f"ADJ-{movement_date.strftime('%Y%m%d')}-{i+1:03d}",
            reason_code=reason_code,
            notes=f"{reason_note} - {ingredient.name}: {'+' if adjustment_quantity > 0 else ''}{adjustment_quantity:.2f} {ingredient.unit_of_measure.value}",
            movement_date=movement_date,
            created_at=movement_date,
            created_by=None  # System-generated
        )
        movements.append(movement)

    return movements


async def create_initial_stock_movements(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    base_date: datetime
) -> list:
    """
    Create INITIAL_STOCK movements for opening inventory

    Represents the initial inventory when the system was set up.

    Args:
        db: Database session
        tenant_id: UUID of the tenant
        base_date: Base reference date for movement calculations

    Returns:
        List of created StockMovement instances
    """
    # Get all stock for this tenant
    result = await db.execute(
        select(Stock, Ingredient).join(
            Ingredient, Stock.ingredient_id == Ingredient.id
        ).where(
            Stock.tenant_id == tenant_id
        )
    )
    stock_items = result.all()

    if not stock_items:
        return []

    movements = []

    # Create initial stock for 20% of ingredients (opening inventory)
    # Date is 60-90 days before base_date
    initial_stock_date = base_date - timedelta(days=random.randint(60, 90))

    # Select 20% of stock items randomly
    num_initial = max(1, int(len(stock_items) * 0.20))
    initial_stock_items = random.sample(stock_items, num_initial)

    for stock, ingredient in initial_stock_items:
        # Initial quantity (50-80% of current quantity)
        initial_quantity = round(stock.current_quantity * random.uniform(0.5, 0.8), 2)

        if initial_quantity < 1.0:
            continue

        # Create initial stock movement
        movement = StockMovement(
            id=uuid.uuid4(),
            tenant_id=tenant_id,
            ingredient_id=ingredient.id,
            stock_id=stock.id,
            movement_type=StockMovementType.INITIAL_STOCK,
            quantity=initial_quantity,
            unit_cost=stock.unit_cost,
            total_cost=stock.unit_cost * Decimal(str(initial_quantity)) if stock.unit_cost else None,
            quantity_before=0.0,
            quantity_after=initial_quantity,
            reference_number=f"INIT-{initial_stock_date.strftime('%Y%m%d')}",
            notes=f"Inventario inicial de {ingredient.name}",
            movement_date=initial_stock_date,
            created_at=initial_stock_date,
            created_by=None  # System-generated
        )
        movements.append(movement)

    return movements


async def seed_stock_for_tenant(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    tenant_name: str,
    base_date: datetime
) -> dict:
    """
    Seed stock batches for all ingredients of a specific tenant

    Args:
        db: Database session
        tenant_id: UUID of the tenant
        tenant_name: Name of the tenant (for logging)
        base_date: Base reference date for expiration calculations

    Returns:
        Dict with seeding statistics
    """
    logger.info("─" * 80)
    logger.info(f"Seeding stock for: {tenant_name}")
    logger.info(f"Tenant ID: {tenant_id}")
    logger.info(f"Base Reference Date: {base_date.isoformat()}")
    logger.info("─" * 80)

    # Check if stock already exists for this tenant (idempotency)
    existing_stock_check = await db.execute(
        select(Stock).where(Stock.tenant_id == tenant_id).limit(1)
    )
    existing_stock = existing_stock_check.scalars().first()

    if existing_stock:
        logger.warning(f"Stock already exists for tenant {tenant_id} - skipping to prevent duplicates")
        # Count existing stock for reporting
        stock_count_result = await db.execute(
            select(Stock).where(Stock.tenant_id == tenant_id)
        )
        existing_stocks = stock_count_result.scalars().all()

        return {
            "tenant_id": str(tenant_id),
            "tenant_name": tenant_name,
            "stock_created": 0,
            "ingredients_processed": 0,
            "skipped": True,
            "existing_stock_count": len(existing_stocks),
            "expired_count": 0,
            "expiring_soon_count": 0,
            "movements_created": 0,
            "purchase_movements": 0,
            "initial_movements": 0,
            "production_movements": 0,
            "adjustment_movements": 0,
            "waste_movements": 0
        }

    # Get all ingredients for this tenant
    result = await db.execute(
        select(Ingredient).where(
            Ingredient.tenant_id == tenant_id,
            Ingredient.is_active == True
        )
    )
    ingredients = result.scalars().all()

    if not ingredients:
        logger.warning(f"No ingredients found for tenant {tenant_id}")
        return {
            "tenant_id": str(tenant_id),
            "tenant_name": tenant_name,
            "stock_created": 0,
            "ingredients_processed": 0
        }

    total_stock_created = 0
    expired_count = 0
    expiring_soon_count = 0

    for ingredient in ingredients:
        stocks = await create_stock_batches_for_ingredient(db, tenant_id, ingredient, base_date)

        for stock in stocks:
            db.add(stock)
            total_stock_created += 1

            if stock.is_expired:
                expired_count += 1
            elif stock.expiration_date:
                days_until_expiry = (stock.expiration_date - base_date).days
                if days_until_expiry <= 3:
                    expiring_soon_count += 1

        logger.debug(f"   ✅ Created {len(stocks)} stock batches for: {ingredient.name}")

    # Commit stock changes
    await db.commit()

    # Create all types of stock movements
    logger.info(f"   📦 Creating stock movements...")

    # 1. Create PURCHASE movements (for all stock received)
    logger.info(f"      💰 Creating purchase movements...")
    purchase_movements = await create_purchase_movements_for_stock(db, tenant_id, base_date)
    for movement in purchase_movements:
        db.add(movement)

    # 2. Create INITIAL_STOCK movements (opening inventory)
    logger.info(f"      📋 Creating initial stock movements...")
    initial_movements = await create_initial_stock_movements(db, tenant_id, base_date)
    for movement in initial_movements:
        db.add(movement)

    # 3. Create PRODUCTION_USE movements (ingredients consumed)
    logger.info(f"      🍞 Creating production use movements...")
    production_movements = await create_production_use_movements(db, tenant_id, base_date)
    for movement in production_movements:
        db.add(movement)

    # 4. Create ADJUSTMENT movements (inventory corrections)
    logger.info(f"      🔧 Creating adjustment movements...")
    adjustment_movements = await create_adjustment_movements(db, tenant_id, base_date)
    for movement in adjustment_movements:
        db.add(movement)

    # 5. Create WASTE movements (spoilage, expiration, etc.)
    logger.info(f"      🗑️  Creating waste movements...")
    waste_movements = await create_waste_movements_for_tenant(db, tenant_id, base_date)
    for movement in waste_movements:
        db.add(movement)

    # Commit all movements
    await db.commit()

    total_movements = (
        len(purchase_movements) +
        len(initial_movements) +
        len(production_movements) +
        len(adjustment_movements) +
        len(waste_movements)
    )

    logger.info(f"   📊 Total Stock Batches Created: {total_stock_created}")
    logger.info(f"   ⚠️  Expired Batches: {expired_count}")
    logger.info(f"   🔔 Expiring Soon (≤3 days): {expiring_soon_count}")
    logger.info(f"   📝 Stock Movements Created: {total_movements}")
    logger.info(f"      💰 Purchase: {len(purchase_movements)}")
    logger.info(f"      📋 Initial Stock: {len(initial_movements)}")
    logger.info(f"      🍞 Production Use: {len(production_movements)}")
    logger.info(f"      🔧 Adjustments: {len(adjustment_movements)}")
    logger.info(f"      🗑️  Waste: {len(waste_movements)}")
    logger.info("")

    return {
        "tenant_id": str(tenant_id),
        "tenant_name": tenant_name,
        "stock_created": total_stock_created,
        "ingredients_processed": len(ingredients),
        "expired_count": expired_count,
        "expiring_soon_count": expiring_soon_count,
        "movements_created": total_movements,
        "purchase_movements": len(purchase_movements),
        "initial_movements": len(initial_movements),
        "production_movements": len(production_movements),
        "adjustment_movements": len(adjustment_movements),
        "waste_movements": len(waste_movements)
    }


async def seed_stock(db: AsyncSession):
    """
    Seed stock for all demo template tenants

    Args:
        db: Database session

    Returns:
        Dict with overall seeding statistics
    """
    logger.info("=" * 80)
    logger.info("📦 Starting Demo Stock Seeding")
    logger.info("=" * 80)

    results = []

    # Seed for San Pablo (Traditional Bakery)
    logger.info("")
    result_san_pablo = await seed_stock_for_tenant(
        db,
        DEMO_TENANT_SAN_PABLO,
        "Panadería San Pablo (Traditional)",
        BASE_REFERENCE_DATE
    )
    results.append(result_san_pablo)

    # Seed for La Espiga (Central Workshop)
    result_la_espiga = await seed_stock_for_tenant(
        db,
        DEMO_TENANT_LA_ESPIGA,
        "Panadería La Espiga (Central Workshop)",
        BASE_REFERENCE_DATE
    )
    results.append(result_la_espiga)

    # Calculate totals
    total_stock = sum(r["stock_created"] for r in results)
    total_expired = sum(r["expired_count"] for r in results)
    total_expiring_soon = sum(r["expiring_soon_count"] for r in results)
    total_movements = sum(r.get("movements_created", r.get("waste_movements_created", 0)) for r in results)

    logger.info("=" * 80)
    logger.info("✅ Demo Stock Seeding Completed")
    logger.info("=" * 80)

    return {
        "service": "inventory",
        "tenants_seeded": len(results),
        "total_stock_created": total_stock,
        "total_expired": total_expired,
        "total_expiring_soon": total_expiring_soon,
        "total_movements_created": total_movements,
        "results": results
    }


async def main():
    """Main execution function"""

    logger.info("Demo Stock Seeding Script Starting")
    logger.info("Mode: %s", os.getenv("DEMO_MODE", "development"))
    logger.info("Log Level: %s", os.getenv("LOG_LEVEL", "INFO"))

    # Get database URL from environment
    database_url = os.getenv("INVENTORY_DATABASE_URL") or os.getenv("DATABASE_URL")
    if not database_url:
        logger.error("❌ INVENTORY_DATABASE_URL or DATABASE_URL environment variable must be set")
        return 1

    # Convert to async URL if needed
    if database_url.startswith("postgresql://"):
        database_url = database_url.replace("postgresql://", "postgresql+asyncpg://", 1)

    logger.info("Connecting to inventory database")

    # Create engine and session
    engine = create_async_engine(
        database_url,
        echo=False,
        pool_pre_ping=True,
        pool_size=5,
        max_overflow=10
    )

    async_session = sessionmaker(
        engine,
        class_=AsyncSession,
        expire_on_commit=False
    )

    try:
        async with async_session() as session:
            result = await seed_stock(session)

            logger.info("")
            logger.info("📊 Seeding Summary:")
            logger.info(f"   ✅ Tenants seeded: {result['tenants_seeded']}")
            logger.info(f"   ✅ Total stock batches:  {result['total_stock_created']}")
            logger.info(f"   ⚠️  Expired batches:  {result['total_expired']}")
            logger.info(f"   🔔 Expiring soon (≤3 days):  {result['total_expiring_soon']}")
            logger.info(f"   📝 Total movements:  {result['total_movements_created']}")
            logger.info("")

            # Print per-tenant details
            for tenant_result in result['results']:
                movements_count = tenant_result.get('movements_created', tenant_result.get('waste_movements_created', 0))
                logger.info(
                    f"   {tenant_result['tenant_name']}: "
                    f"{tenant_result['stock_created']} batches "
                    f"({tenant_result['expired_count']} expired, "
                    f"{tenant_result['expiring_soon_count']} expiring soon, "
                    f"{movements_count} movements)"
                )

            logger.info("")
            logger.info("🎉 Success! Stock data ready for cloning and alert generation.")
            logger.info("")
            logger.info("Next steps:")
            logger.info("  1. Update inventory clone endpoint to include stock")
            logger.info("  2. Implement date offset during cloning")
            logger.info("  3. Generate expiration alerts during clone")
            logger.info("  4. Test demo session creation")
            logger.info("")

            return 0

    except Exception as e:
        logger.error("=" * 80)
        logger.error("❌ Demo Stock Seeding Failed")
        logger.error("=" * 80)
        logger.error("Error: %s", str(e))
        logger.error("", exc_info=True)
        return 1

    finally:
        await engine.dispose()


if __name__ == "__main__":
    exit_code = asyncio.run(main())
    sys.exit(exit_code)
