# generar_dataset_ecomm.py
# Manual Teradata -- Capitulo 12
# Descripcion: Genera los archivos CSV del dataset de e-commerce.
#
# PRODUCTOS: usa el catalogo real de gondola argentina (Libro1.csv)
#            con precios, marcas y descripciones reales.
#            Si no encuentra el archivo, usa datos sinteticos de respaldo.
#
# Archivos generados:
#   clientes.csv   -->  50.000 filas
#   productos.csv  -->   5.000 filas (sample del catalogo real)
#   pedidos_1M.csv --> 1.000.000 filas
#   pagos.csv      --> ~950.000 filas (excluye cancelados)
#
# Uso:
#   python generar_dataset_ecomm.py [--catalogo ruta/Libro1.csv]
#
# Requisitos: Python 3.8+, solo stdlib

import csv
import random
import datetime
import sys
import os
from pathlib import Path

random.seed(42)

# --- Datos de referencia -----------------------------------------------------
REGIONES = [
    'AMBA', 'Cordoba', 'Rosario', 'Mendoza', 'Tucuman',
    'Salta', 'Mar del Plata', 'Neuquen', 'Bariloche', 'La Plata'
]
CANALES   = ['WEB', 'APP', 'MKTPLACE', 'TELEVENTAS']
ESTADOS   = (['ENTREGADO']*60 + ['ENVIADO']*20 +
             ['PENDIENTE']*12 + ['CANCELADO']*8)
METODOS   = (['TARJETA']*45 + ['MP']*30 +
             ['TRANSFERENCIA']*20 + ['CRYPTO']*5)
SEGMENTOS = (['STANDARD']*50 + ['SILVER']*30 +
             ['GOLD']*15     + ['PLATINUM']*5)
CUOTAS    = [1, 3, 6, 12, 18, 24]
EST_PAGO  = ['APROBADO']*90 + ['RECHAZADO']*5 + ['PENDIENTE']*5

OUTPUT_DIR = Path('.')

# --- Reglas de categorias para el catalogo argentino -------------------------
CATEGORIAS_REGLAS = {
    'Bebidas':          ['AGUA','JUGO','GASEOSA','CERVEZA','VINO','FERNET',
                         'WHISKY','COCA','PEPSI','SPRITE','POWERADE','LEVITE',
                         'APERITIVO','VODKA','GIN','SIDRA','LICOR','SODA',
                         'PISCO','PASO/TOROS','SAB ','CITRIC','TANG ',
                         'GATORADE','MONSTER','RED BULL','ENERGIZANTE',
                         'TONICA','AMARGO','BITTER','ROM ','RUM ','TEQUILA'],
    'Lacteos':          ['LECHE','YOGUR','QUESO','CREMA','MANTECA',
                         'DULCE DE LECHE','RICOTA','CREME','POSTRE',
                         'SERENITO','FLAN','MOUSSE','CHOCOBOMBA','DANETTE',
                         'POTE ','ILOLAY','LA SERENISIMA','SANCOR','DDL'],
    'Almacen':          ['ACEITE','ARROZ','FIDEOS','HARINA','AZUCAR','SAL ',
                         'TOMATE','YERBA','MATE ','LENTEJAS','POROTOS',
                         'GARBANZOS','ARVEJAS','LENTEJ','OLINTO',
                         'VINAGRE','MAYONESA','MOSTAZA','KETCHUP','POLENTA',
                         'AVENA','COPOS','GRANOLA','MIEL ','MERMELADA',
                         'DULCE ','DCE ','JALEA','PURE','PURE ','SOPA',
                         'CALDO','SALSA','ACEIT VDE','GIRASOL','MAIZ PISI',
                         'ZANAHORIA','COOPERA','ALCAUCIL','CHOCLO','LEGUM'],
    'Galletitas':       ['GALLETITA','GALL ','GALL.','OBLEA','ALFAJOR',
                         'ALF.','TOSTADA','DONUTS','MELBA','BIZCOCHO',
                         'CUBANITO','PEPITOS','TERRIBUS','OREO','RHODESIA',
                         'FACTURAS','MEDIALUNAS','FACTURA'],
    'Golosinas':        ['CHOCOLATE','CARAMELO','SUGUS','CHUPETE','CHICLE',
                         'GOMITAS','TURRON','GARRAPINAD','CONFITE','CHOC ',
                         'CHOC.','COFLER','BON O BON','PALITOS','ROCKLETS',
                         'PALERMO','BATATA ARCOR'],
    'Snacks':           ['PAPAS FRITAS','CHIZITO','PALOMITA','MAIZ INFLADO',
                         'SNACK','POP ','NACHOS','MAICITOS'],
    'Limpieza Hogar':   ['DETERGENTE','LAVANDINA','SUAVIZANTE','LIMPIADOR',
                         'DESENGRASANTE','VIM','CLOROX','MAGISTRAL','LYSOFORM',
                         'ESPONJA','FIBRA ','TRAPO','ESCOBA','PLUMERO',
                         'PROCENEX','ODEX','ROLLO FEL','FRANELA','ALCOHOL',
                         'JAB PVO','JABON POL','BIALCOHOL','ALA ','SKIP ',
                         'DRIVE ','MAGISTR','CEPILLO COOP','LAMPAZO'],
    'Cuidado Personal': ['SHAMPOO','SH ','ACONDICIONADOR','AC ','AMP ',
                         'DESODORANTE','ANT ','PERFUME','CREMA FACIAL',
                         'PASTA DENTAL','CEPILLO DENT','JABON LIQ',
                         'JABON TOCAD','AFTER SHAVE','MAQUINA AFEIT',
                         'ISSUE ','PANTENE','FRUCTIS','ELVIVE','SEDAL',
                         'HEAD&SHOU','HEAD &','DOVE ','NIVEA','GARNIER',
                         'POLYANA','CR ','MASCARA','HISOPO'],
    'Higiene Bebe':     ['PANAL','TOALLITA','CREMA BEBE','TALCO','MAMILA',
                         'PAMPERS','HUGGIES'],
    'Carnes':           ['SALCHI','JAMON','MORTADELA','CHORIZO','SALAME',
                         'PESCADO','ATUN','SARDINA','CABALLA','MEJILLON',
                         'VIENISSIMA','PATITAS','NUGGET','MILANESA'],
    'Panaderia':        ['PAN LAC','PAN BLA','PAN INT','PAN ART',
                         'TOSTADO','BIMBO','LACTAL'],
    'Congelados':       ['HELADO','EMPANADA','PIZZA','BURGUER','CONGEL',
                         'CHORIPAN','PALITO HELA'],
    'Especias':         ['OREGANO','PIMIENT','COMINO','LAUREL','CANELA',
                         'CONDIMENTO','ESPECIAS','AJI MOLIDO','ALBAHACA',
                         'PIMIENTA','PRIMER PRECIO'],
    'Electro y Hogar':  ['CEL ','CELULAR','NOTEBOOK','MICROONDAS','LAMPARA',
                         'LED ','CARGADOR','AURICULAR','TABLET','TV '],
    'Ferreteria':       ['PILA ','BATERIA','PEGAMENTO','SILICONA',
                         'CINTA ADHE','FOCOS','LAMPARITA'],
}

def inferir_categoria(descripcion):
    desc = descripcion.upper()
    for cat, claves in CATEGORIAS_REGLAS.items():
        if any(c in desc for c in claves):
            return cat
    return 'Otros'

def inferir_subcategoria(descripcion, categoria):
    """Subcategoria basada en la primera palabra significativa del producto."""
    palabras = descripcion.strip().split()
    if len(palabras) >= 2:
        return ' '.join(palabras[:2]).title()
    return descripcion[:30].title()

NOMBRES_M = [
    'Juan','Carlos','Luis','Miguel','Pablo','Diego','Alejandro','Martin',
    'Sebastian','Gabriel','Federico','Nicolas','Andres','Ricardo','Daniel',
    'Sergio','Fernando','Matias','Ezequiel','Facundo','Leandro','Gustavo',
    'Ramiro','Cristian','Santiago','Ignacio','Hernan','Roberto','Marcelo',
    'Gonzalo','Leonardo','Maximiliano','Bruno','Franco','Agustin','Rodrigo'
]
NOMBRES_F = [
    'Maria','Laura','Ana','Patricia','Claudia','Valeria','Gabriela','Florencia',
    'Natalia','Veronica','Carolina','Romina','Silvana','Daniela','Luciana',
    'Mariana','Vanessa','Paola','Cecilia','Monica','Carla','Sofia','Valentina',
    'Camila','Jimena','Soledad','Alejandra','Graciela','Adriana','Paula',
    'Micaela','Julieta','Agustina','Belen','Noelia','Rocio'
]
NOMBRES_X = ['Alex','Jamie','Morgan','Sam','Taylor','Jordan','Casey','Riley']

APELLIDOS = [
    'Gonzalez','Rodriguez','Gomez','Fernandez','Lopez','Martinez','Garcia',
    'Perez','Sanchez','Romero','Sosa','Torres','Diaz','Reyes','Flores',
    'Alvarez','Ruiz','Morales','Jimenez','Herrera','Medina','Castro','Ortiz',
    'Vargas','Delgado','Mendoza','Ramos','Suarez','Molina','Silva','Rojas',
    'Acosta','Gutierrez','Cabrera','Rios','Vega','Aguirre','Paz','Pereyra',
    'Nunez','Juarez','Munoz','Blanco','Benitez','Figueroa','Leiva','Ponce'
]

DOMINIOS = [
    'gmail.com','gmail.com','gmail.com',
    'hotmail.com','hotmail.com',
    'yahoo.com','yahoo.com.ar',
    'outlook.com','live.com',
    'icloud.com','proton.me'
]

def rand_cliente(genero):
    if genero == 'M':
        nombre = random.choice(NOMBRES_M)
    elif genero == 'F':
        nombre = random.choice(NOMBRES_F)
    else:
        nombre = random.choice(NOMBRES_X)
    apellido  = random.choice(APELLIDOS)
    nombre_completo = f"{nombre} {apellido}"
    dominio   = random.choice(DOMINIOS)
    sufijo    = str(random.randint(1, 999)) if random.random() < 0.4 else ''
    variante  = random.randint(1, 4)
    nom_l     = nombre.lower()
    ape_l     = apellido.lower()
    if variante == 1:
        usuario = f"{nom_l}{sufijo}"
    elif variante == 2:
        usuario = f"{nom_l}.{ape_l}{sufijo}"
    elif variante == 3:
        usuario = f"{nom_l[0]}{ape_l}{sufijo}"
    else:
        usuario = f"{ape_l}{sufijo}"
    email = f"{usuario}@{dominio}"
    return nombre_completo, email

def rand_date(start='2022-01-01', end='2025-06-30'):
    d1 = datetime.date.fromisoformat(start)
    d2 = datetime.date.fromisoformat(end)
    return d1 + datetime.timedelta(days=random.randint(0, (d2-d1).days))


# --- PASO 1: Leer catalogo real -----------------------------------------------
# Buscar Libro1.csv en el directorio actual o en el argumento pasado
catalogo_path = None
for arg in sys.argv[1:]:
    if arg.startswith('--catalogo'):
        catalogo_path = arg.split('=')[-1] if '=' in arg else sys.argv[sys.argv.index(arg)+1]

if catalogo_path is None:
    # Buscar automaticamente
    candidatos = [
        Path('Libro1.csv'),
        Path('../Libro1.csv'),
        Path('/data/Libro1.csv'),
    ]
    for c in candidatos:
        if c.exists():
            catalogo_path = c
            break

USAR_CATALOGO_REAL = catalogo_path is not None and Path(catalogo_path).exists()

productos_raw = []

if USAR_CATALOGO_REAL:
    print(f"Leyendo catalogo real: {catalogo_path}")
    with open(catalogo_path, encoding='utf-8') as f:
        r = csv.DictReader(f, delimiter=';')
        for row in r:
            try:
                precio = float(row['productos_precio_lista'].replace(',','.'))
                if precio <= 0 or precio > 500000:
                    continue
                marca = row['productos_marca'].strip()
                desc  = row['productos_descripcion'].strip()
                if not marca or not desc:
                    continue
                productos_raw.append({
                    'nombre':   desc[:200],
                    'marca':    marca[:60],
                    'precio':   precio,
                    'unidad':   row['productos_unidad_medida_presentacion'].strip(),
                })
            except (ValueError, KeyError):
                continue
    print(f"  Productos validos en catalogo: {len(productos_raw):,}")
else:
    print("AVISO: No se encontro Libro1.csv -- usando productos sinteticos de respaldo.")
    print("       Para usar el catalogo real: python generar_dataset_ecomm.py --catalogo=Libro1.csv")

# --- PASO 2: Samplear 5.000 productos del catalogo ---------------------------
# Tomar una muestra representativa: diversa en marcas y categorias
print("\nGenerando productos.csv (5.000 productos)...")

productos_path = OUTPUT_DIR / 'productos.csv'

with open(productos_path, 'w', newline='', encoding='utf-8') as f:
    w = csv.writer(f)
    w.writerow(['producto_id','nombre','categoria','subcategoria',
                'marca','precio_base','costo','activo'])

    if USAR_CATALOGO_REAL and len(productos_raw) >= 5000:
        # Samplear 5.000 sin repeticion, con shuffle para diversidad
        muestra = random.sample(productos_raw, 5000)
        for i, prod in enumerate(muestra, start=1):
            cat  = inferir_categoria(prod['nombre'])
            sub  = inferir_subcategoria(prod['nombre'], cat)
            prec = round(prod['precio'], 2)
            cost = round(prec * 0.55, 2)
            w.writerow([i, prod['nombre'], cat, sub,
                        prod['marca'], prec, cost, 1])
        print(f"  OK -- 5.000 productos reales del catalogo argentino")
    else:
        # Respaldo sintetico
        CATS_SINT = {
            'Bebidas':    ['Agua','Jugo','Gaseosa','Cerveza','Vino'],
            'Lacteos':    ['Leche','Yogur','Queso','Crema','Manteca'],
            'Almacen':    ['Aceite','Arroz','Fideos','Harina','Yerba'],
            'Galletitas': ['Dulce','Salada','Oblea','Alfajor'],
            'Limpieza':   ['Detergente','Lavandina','Suavizante'],
            'Cuidado':    ['Shampoo','Desodorante','Jabon'],
        }
        for i in range(1, 5001):
            cat = random.choice(list(CATS_SINT.keys()))
            sub = random.choice(CATS_SINT[cat])
            p   = round(random.uniform(200, 15000), 2)
            w.writerow([i, f'{sub} Marca_{i}', cat, sub,
                        f'Marca_{random.randint(1,50)}',
                        p, round(p*0.55,2), 1])
        print(f"  OK -- 5.000 productos sinteticos (catalogo no encontrado)")

# --- PASO 3: Clientes (50.000) -----------------------------------------------
print("\nGenerando clientes.csv (50.000 clientes)...")
clientes_path = OUTPUT_DIR / 'clientes.csv'
with open(clientes_path, 'w', newline='', encoding='utf-8') as f:
    w = csv.writer(f)
    w.writerow(['cliente_id','nombre','email','pais','region',
                'ciudad','segmento','fecha_alta','genero','activo'])
    for i in range(1, 50001):
        genero = random.choice(['M','M','F','F','X'])  # distribucion realista
        nombre_completo, email = rand_cliente(genero)
        w.writerow([
            i, nombre_completo, email,
            'Argentina', random.choice(REGIONES),
            f'Ciudad_{random.randint(1,20)}',
            random.choice(SEGMENTOS),
            rand_date('2018-01-01','2024-12-31'),
            genero, 1
        ])
print(f"  OK -- 50.000 clientes")

# --- PASO 4: Pedidos (1.000.000) ---------------------------------------------
print("\nGenerando pedidos_1M.csv (1.000.000 pedidos)...")
pedidos_path = OUTPUT_DIR / 'pedidos_1M.csv'
pedidos_ref  = []

with open(pedidos_path, 'w', newline='', encoding='utf-8') as f:
    w = csv.writer(f)
    w.writerow(['pedido_id','cliente_id','producto_id','fecha_pedido',
                'cantidad','precio_unitario','descuento_pct',
                'monto_bruto','monto_descuento','monto_total',
                'estado','canal','region','tiempo_entrega'])
    for i in range(1, 1_000_001):
        cid    = random.randint(1, 50000)
        pid    = random.randint(1, 5000)
        fecha  = rand_date()
        qty    = random.randint(1, 5)
        precio = round(random.uniform(200, 50000), 2)
        desc   = random.choice([0, 0, 0, 5, 10, 15, 20, 25])
        bruto  = round(precio * qty, 2)
        dscto  = round(bruto * desc / 100, 2)
        total  = round(bruto - dscto, 2)
        estado = random.choice(ESTADOS)
        entrega = random.randint(1, 15) if estado == 'ENTREGADO' else 0
        w.writerow([i, cid, pid, fecha, qty, precio, desc,
                    bruto, dscto, total,
                    estado, random.choice(CANALES),
                    random.choice(REGIONES), entrega])
        pedidos_ref.append((i, cid, total, estado))
        if i % 100000 == 0:
            print(f"  {i:>9,} pedidos generados...")

print(f"  OK -- 1.000.000 pedidos")

# --- PASO 5: Pagos (~950.000) ------------------------------------------------
print("\nGenerando pagos.csv...")
pagos_path = OUTPUT_DIR / 'pagos.csv'
pago_id = 1
with open(pagos_path, 'w', newline='', encoding='utf-8') as f:
    w = csv.writer(f)
    w.writerow(['pago_id','pedido_id','cliente_id','fecha_pago',
                'monto_pagado','metodo_pago','cuotas','estado_pago'])
    for ped_id, cli_id, total, estado in pedidos_ref:
        if estado == 'CANCELADO':
            continue
        w.writerow([pago_id, ped_id, cli_id, rand_date(),
                    total, random.choice(METODOS),
                    random.choice(CUOTAS),
                    random.choice(EST_PAGO)])
        pago_id += 1

print(f"  OK -- {pago_id-1:,} pagos")

# --- Resumen -----------------------------------------------------------------
print("\n=== Dataset generado exitosamente ===")
fuente = "catalogo real argentino" if USAR_CATALOGO_REAL else "datos sinteticos"
print(f"  productos.csv  -->   5.000 filas  ({fuente})")
print(f"  clientes.csv   -->  50.000 filas")
print(f"  pedidos_1M.csv --> 1.000.000 filas")
print(f"  pagos.csv      --> {pago_id-1:,} filas")
print(f"\nProximo paso: ejecutar los scripts FastLoad")
print(f"  fastload < fastload_clientes.fl")
print(f"  fastload < fastload_productos.fl")
print(f"  fastload < fastload_pedidos.fl")
print(f"  fastload < fastload_pagos.fl")
