#!/usr/bin/env python3
"""
Marketplace seed script — populates the DB with realistic test data so you
can exercise the marketplace UI end-to-end from a browser.

What it creates:
  - 3 bodegas in different cities (all pre-verified)
  - ~60 warehouse_inventory rows spread across the 3 bodegas
  - 1 new employee in tenant_refaccionaria_demo configured as seller for bodega #1
    (PIN: 9999)
  - 3 purchase orders in different states (submitted, confirmed, delivered)

After running, you can log into the POS:
  - As buyer: Ivan Alcaraz (existing owner) — to test Explorar + Mis Pedidos
  - As seller: "Bodega Test Seller" (new) PIN 9999 — to test Inbox + Inventario

Run:
    cd /home/Autopartes/pos && python3 ../scripts/seed_marketplace.py

Safe to re-run: the script cleans up prior seed data before re-inserting.
"""

import os
import sys
import bcrypt

# Ensure we can import from the POS package
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'pos'))

from tenant_db import get_master_conn, get_tenant_conn
from services import marketplace_service as mkt


# ═══════════════════════════════════════════════════════════════════════════
# CONFIG — tweak these if you want different seed data
# ═══════════════════════════════════════════════════════════════════════════

TENANT_ID = 11                  # tenant_refaccionaria_demo
SELLER_PIN = '9999'             # login PIN for the seed seller employee
SELLER_NAME = 'Bodega Test Seller'
SELLER_EMAIL = 'seller@bodegatest.mx'

BODEGAS = [
    {
        'name': 'Bodega Central Tijuana',
        'owner_name': 'Juan Perez',
        'whatsapp_phone': '5216641230001',
        'email': 'juan@bodegacentral.mx',
        'city': 'Tijuana',
        'state': 'BC',
        'address': 'Blvd. Industrial 1234, Col. Otay, Tijuana BC',
    },
    {
        'name': 'Refacciones del Norte GDL',
        'owner_name': 'Maria Gonzalez',
        'whatsapp_phone': '5213311230002',
        'email': 'maria@refnorte.mx',
        'city': 'Guadalajara',
        'state': 'JAL',
        'address': 'Av. Vallarta 5678, Zapopan JAL',
    },
    {
        'name': 'AutoPartes del Bajio CDMX',
        'owner_name': 'Carlos Torres',
        'whatsapp_phone': '5215511230003',
        'email': 'carlos@autopartesbajio.mx',
        'city': 'Ciudad de Mexico',
        'state': 'CDMX',
        'address': 'Eje 5 Norte 910, Azcapotzalco CDMX',
    },
]


# ═══════════════════════════════════════════════════════════════════════════
# HELPERS
# ═══════════════════════════════════════════════════════════════════════════

def log(msg):
    print(f'  → {msg}')


def hash_pin(pin: str) -> str:
    return bcrypt.hashpw(pin.encode(), bcrypt.gensalt()).decode()


# ═══════════════════════════════════════════════════════════════════════════
# CLEANUP — remove previous seed data before re-inserting
# ═══════════════════════════════════════════════════════════════════════════

def cleanup(master_conn, tenant_conn):
    """Remove previous seed data so re-running the script is idempotent."""
    log('Cleaning up previous seed data...')

    # Tenant side: remove the seed seller employee
    cur = tenant_conn.cursor()
    cur.execute("DELETE FROM employees WHERE email = %s", (SELLER_EMAIL,))
    tenant_conn.commit()
    cur.close()

    # Master side: remove any bodegas with the seed names
    cur = master_conn.cursor()
    names = tuple(b['name'] for b in BODEGAS)
    # Cascade will clean up purchase_orders, po_items, po_status_history,
    # and warehouse_inventory rows referencing these bodegas.
    # warehouse_inventory's FK to bodegas is not CASCADE — handle manually.
    cur.execute("""
        DELETE FROM warehouse_inventory
        WHERE bodega_id IN (SELECT id_bodega FROM bodegas WHERE name = ANY(%s))
    """, (list(names),))
    cur.execute("""
        DELETE FROM purchase_orders
        WHERE bodega_id IN (SELECT id_bodega FROM bodegas WHERE name = ANY(%s))
    """, (list(names),))
    cur.execute("DELETE FROM bodegas WHERE name = ANY(%s)", (list(names),))
    master_conn.commit()
    cur.close()
    log('Cleanup complete.')


# ═══════════════════════════════════════════════════════════════════════════
# STEP 1 — Create bodegas (pre-verified)
# ═══════════════════════════════════════════════════════════════════════════

def create_bodegas(master_conn) -> list[int]:
    bodega_ids = []
    for b in BODEGAS:
        bid = mkt.create_bodega(
            master_conn,
            name=b['name'],
            owner_name=b['owner_name'],
            whatsapp_phone=b['whatsapp_phone'],
            email=b['email'],
            city=b['city'],
            state=b['state'],
            address=b['address'],
        )
        mkt.verify_bodega(master_conn, bid)
        bodega_ids.append(bid)
        log(f'Created+verified bodega #{bid}: {b["name"]}')
    master_conn.commit()
    return bodega_ids


# ═══════════════════════════════════════════════════════════════════════════
# STEP 2 — Populate warehouse_inventory
# ═══════════════════════════════════════════════════════════════════════════

def populate_inventory(master_conn, bodega_ids: list[int]):
    """Pick ~60 real OEM parts from the catalog, split across the 3 bodegas
    with pseudo-realistic price and stock levels.

    warehouse_inventory has an FK on user_id → users(id_user). We use a
    single master user as the legacy owner AND differentiate bodegas via
    a composite (user_id, part_id, warehouse_location) key where
    warehouse_location becomes "Bodega#{bodega_id}" so different bodegas
    can hold the same part without violating the UNIQUE constraint.
    """
    cur = master_conn.cursor()

    # Resolve a valid user_id for the FK (doesn't matter which — we use it
    # as a plumbing placeholder only; the real ownership is via bodega_id).
    cur.execute("SELECT id_user FROM users ORDER BY id_user LIMIT 1")
    row = cur.fetchone()
    if not row:
        cur.close()
        log('WARN: no users in master DB — cannot seed inventory')
        return
    owner_user_id = row[0]

    # Grab 60 popular parts (prefer those with aftermarket equivalents so the
    # buyer gets meaningful data when they open the detail view).
    cur.execute("""
        SELECT p.id_part, p.oem_part_number, p.name_part
        FROM parts p
        JOIN aftermarket_parts ap ON ap.oem_part_id = p.id_part
        WHERE p.oem_part_number IS NOT NULL
        GROUP BY p.id_part, p.oem_part_number, p.name_part
        ORDER BY COUNT(ap.id_aftermarket_parts) DESC
        LIMIT 60
    """)
    parts = cur.fetchall()
    cur.close()

    import random
    random.seed(42)

    rows_inserted = 0
    for i, (part_id, oem, name) in enumerate(parts):
        bodega_count = random.choice([1, 1, 2, 2, 3])
        bodegas_for_this_part = random.sample(bodega_ids, bodega_count)

        for bid in bodegas_for_this_part:
            price = round(random.uniform(50, 3500), 2)
            stock = random.randint(1, 20)
            location = f'Bodega#{bid}'  # unique per bodega → no conflict

            # Each insert gets its own cursor + savepoint so one failure
            # doesn't abort the whole transaction.
            try:
                cur2 = master_conn.cursor()
                cur2.execute("""
                    INSERT INTO warehouse_inventory
                        (user_id, part_id, price, stock_quantity, min_order_quantity,
                         warehouse_location, bodega_id, currency, updated_at)
                    VALUES (%s, %s, %s, %s, 1, %s, %s, 'MXN', NOW())
                    ON CONFLICT (user_id, part_id, warehouse_location) DO UPDATE
                    SET price = EXCLUDED.price,
                        stock_quantity = EXCLUDED.stock_quantity,
                        bodega_id = EXCLUDED.bodega_id,
                        updated_at = NOW()
                """, (owner_user_id, part_id, price, stock, location, bid))
                master_conn.commit()
                cur2.close()
                rows_inserted += 1
            except Exception as e:
                master_conn.rollback()
                if rows_inserted < 3:  # only log the first few to avoid spam
                    print(f'    inventory insert failed for part {part_id}: {str(e)[:120]}')

    log(f'Populated {rows_inserted} warehouse_inventory rows across {len(bodega_ids)} bodegas')


# ═══════════════════════════════════════════════════════════════════════════
# STEP 3 — Create a seller employee
# ═══════════════════════════════════════════════════════════════════════════

def create_seller_employee(tenant_conn, bodega_id: int) -> int:
    cur = tenant_conn.cursor()
    pin_hash = hash_pin(SELLER_PIN)
    cur.execute("""
        INSERT INTO employees
            (name, email, role, marketplace_role, bodega_id, is_active, pin, password_hash)
        VALUES (%s, %s, 'employee', 'seller', %s, TRUE, %s, %s)
        RETURNING id
    """, (SELLER_NAME, SELLER_EMAIL, bodega_id, pin_hash, pin_hash))
    emp_id = cur.fetchone()[0]
    tenant_conn.commit()
    cur.close()
    log(f'Created seller employee #{emp_id} "{SELLER_NAME}" for bodega #{bodega_id} (PIN: {SELLER_PIN})')
    return emp_id


# ═══════════════════════════════════════════════════════════════════════════
# STEP 4 — Create sample POs in different states
# ═══════════════════════════════════════════════════════════════════════════

def create_sample_pos(master_conn, bodega_ids: list[int]):
    """Create 3 POs in states: submitted, confirmed, delivered."""
    cur = master_conn.cursor()
    cur.execute("""
        SELECT p.id_part FROM parts p
        JOIN warehouse_inventory wi ON wi.part_id = p.id_part
        WHERE wi.bodega_id = %s
        LIMIT 3
    """, (bodega_ids[0],))
    sample_parts = [row[0] for row in cur.fetchall()]
    cur.close()

    if not sample_parts:
        log('WARN: no sample parts for PO seed, skipping')
        return

    # PO 1 — submitted (waiting for seller to confirm)
    po1 = mkt.create_po_draft(
        master_conn,
        buyer_tenant_id=TENANT_ID, buyer_user_id=1,
        buyer_display_name='Ivan Alcaraz',
        buyer_phone='5216649998877',
        buyer_email='ivan@demo.mx',
        bodega_id=bodega_ids[0],
        items=[
            {'part_id': sample_parts[0], 'quantity': 2, 'unit_price': 250.00},
            {'part_id': sample_parts[1], 'quantity': 1, 'unit_price': 850.00},
        ],
        delivery_method='pickup',
        buyer_notes='Urgente — cliente esperando',
    )
    mkt.transition_po(master_conn, po_id=po1, new_status='submitted',
                      actor_user_id=1, actor_kind='buyer', note='Enviado')
    log(f'Created PO #{po1} in state: submitted')

    # PO 2 — confirmed (seller accepted, preparing)
    po2 = mkt.create_po_draft(
        master_conn,
        buyer_tenant_id=TENANT_ID, buyer_user_id=1,
        buyer_display_name='Ivan Alcaraz',
        buyer_phone='5216649998877',
        buyer_email='ivan@demo.mx',
        bodega_id=bodega_ids[0],
        items=[
            {'part_id': sample_parts[2], 'quantity': 3, 'unit_price': 420.00},
        ],
        delivery_method='delivery',
        delivery_address='Refaccionaria Demo, Av. Revolucion 100, Tijuana',
        buyer_notes='Entregar en la tarde',
    )
    mkt.transition_po(master_conn, po_id=po2, new_status='submitted',
                      actor_user_id=1, actor_kind='buyer')
    mkt.transition_po(master_conn, po_id=po2, new_status='confirmed',
                      actor_user_id=99, actor_kind='seller',
                      note='Confirmado — preparando pedido')
    log(f'Created PO #{po2} in state: confirmed')

    # PO 3 — delivered (full happy path, closed)
    po3 = mkt.create_po_draft(
        master_conn,
        buyer_tenant_id=TENANT_ID, buyer_user_id=1,
        buyer_display_name='Ivan Alcaraz',
        buyer_phone='5216649998877',
        buyer_email='ivan@demo.mx',
        bodega_id=bodega_ids[1],  # different bodega
        items=[
            {'part_id': sample_parts[0], 'quantity': 1, 'unit_price': 175.50},
        ],
        delivery_method='pickup',
    )
    for new_state, kind in [('submitted', 'buyer'), ('confirmed', 'seller'),
                             ('ready', 'seller'), ('delivered', 'buyer')]:
        mkt.transition_po(master_conn, po_id=po3, new_status=new_state,
                          actor_user_id=1 if kind == 'buyer' else 99,
                          actor_kind=kind)
    log(f'Created PO #{po3} in state: delivered')


# ═══════════════════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════════════════

def main():
    print('╔══════════════════════════════════════════════╗')
    print('║ Nexus Marketplace — Seed Script              ║')
    print('╚══════════════════════════════════════════════╝')
    print()

    master_conn = get_master_conn()
    tenant_conn = get_tenant_conn(TENANT_ID)
    try:
        cleanup(master_conn, tenant_conn)

        print()
        print('STEP 1 — Create bodegas')
        bodega_ids = create_bodegas(master_conn)

        print()
        print('STEP 2 — Populate warehouse_inventory')
        populate_inventory(master_conn, bodega_ids)

        print()
        print('STEP 3 — Create seller employee')
        seller_id = create_seller_employee(tenant_conn, bodega_ids[0])

        print()
        print('STEP 4 — Create sample POs')
        create_sample_pos(master_conn, bodega_ids)

        print()
        print('╔══════════════════════════════════════════════╗')
        print('║                    DONE                      ║')
        print('╚══════════════════════════════════════════════╝')
        print()
        print('Log in at http://localhost:5001/pos/login with:')
        print()
        print(f'  BUYER (Ivan Alcaraz — existing owner)')
        print(f'    PIN: (your existing PIN)')
        print(f'    Test at: http://localhost:5001/pos/marketplace')
        print(f'    Should see: Explorar + Mis Pedidos tabs')
        print()
        print(f'  SELLER ({SELLER_NAME})')
        print(f'    Email: {SELLER_EMAIL}')
        print(f'    PIN: {SELLER_PIN}')
        print(f'    Test at: http://localhost:5001/pos/marketplace')
        print(f'    Should see: Pedidos Recibidos + Mi Inventario + Explorar')
        print()
        print(f'Bodegas created: #{bodega_ids[0]} (Tijuana), '
              f'#{bodega_ids[1]} (Guadalajara), #{bodega_ids[2]} (CDMX)')
    finally:
        master_conn.close()
        tenant_conn.close()


if __name__ == '__main__':
    main()
