# -*- coding: utf-8 -*-
# ============================================================
#  generar_dataset_ecomm.py
#  Genera CSVs coherentes para el esquema estrella del manual.
#  Serie JAVIESCA --- Manual de Modelado Dimensional
# ============================================================
#  Diseno pensado para ILUSTRAR el manual:
#    - miembro -1 'Desconocido' en cada dimension
#    - dim_cliente con 2 clientes en version SCD Tipo 2 (cambio
#      de provincia -> dos filas, es_actual 0/1)
#    - dim_fecha en role-playing (pedido y pago apuntan a ella)
#    - nro_pedido como dimension degenerada en la fact
#  Salida: dataset/csv/*.csv
# ============================================================

import os
import csv
import random
from datetime import date, timedelta

random.seed(42)  # reproducible

DIR = os.path.dirname(__file__)
OUT = os.path.join(DIR, "csv")
os.makedirs(OUT, exist_ok=True)

NOMBRE_MES = ["", "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
              "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]
NOMBRE_DIA = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"]


def escribir(nombre, cabecera, filas):
    ruta = os.path.join(OUT, nombre)
    with open(ruta, "w", newline="", encoding="utf-8") as f:
        w = csv.writer(f)
        w.writerow(cabecera)
        w.writerows(filas)
    print("  [OK] %-22s %5d filas" % (nombre, len(filas)))


# ------------------------------------------------------------
# dim_fecha (2024-01-01 .. 2025-12-31)
# ------------------------------------------------------------
def gen_dim_fecha():
    filas = [[-1, "1900-01-01", 1900, 1, 1, "Desconocido", 1, 1, "Desconocido", 0, "1900-01"]]
    d = date(2024, 1, 1)
    fin = date(2025, 12, 31)
    while d <= fin:
        dow = d.weekday()  # 0=lunes
        sk = d.year * 10000 + d.month * 100 + d.day
        filas.append([
            sk, d.isoformat(), d.year, (d.month - 1) // 3 + 1, d.month,
            NOMBRE_MES[d.month], d.day, dow + 1, NOMBRE_DIA[dow],
            1 if dow >= 5 else 0, "%04d-%02d" % (d.year, d.month),
        ])
        d += timedelta(days=1)
    escribir("dim_fecha.csv",
             ["fecha_sk", "fecha", "anio", "trimestre", "mes", "nombre_mes",
              "dia", "dia_semana", "nombre_dia", "es_fin_semana", "anio_mes"], filas)
    return [f[0] for f in filas[1:]]  # sk validos (sin -1)


# ------------------------------------------------------------
# dim_geografia (ciudades AR con ISO 3166-2)
# ------------------------------------------------------------
GEO = [
    ("La Plata", "Buenos Aires", "AR-B", "Centro"),
    ("Mar del Plata", "Buenos Aires", "AR-B", "Centro"),
    ("CABA", "Ciudad Autonoma de Buenos Aires", "AR-C", "Centro"),
    ("Cordoba", "Cordoba", "AR-X", "Centro"),
    ("Rosario", "Santa Fe", "AR-S", "Centro"),
    ("Mendoza", "Mendoza", "AR-M", "Cuyo"),
    ("San Miguel de Tucuman", "Tucuman", "AR-T", "Norte"),
    ("Salta", "Salta", "AR-A", "Norte"),
    ("Neuquen", "Neuquen", "AR-Q", "Patagonia"),
    ("Bariloche", "Rio Negro", "AR-R", "Patagonia"),
]


def gen_dim_geografia():
    filas = [[-1, "Desconocido", "Desconocido", "N/D", "Desconocido"]]
    for i, (ciu, prov, iso, reg) in enumerate(GEO, start=1):
        filas.append([i, ciu, prov, iso, reg])
    escribir("dim_geografia.csv",
             ["geografia_sk", "ciudad", "provincia", "codigo_iso", "region"], filas)
    return [f[0] for f in filas[1:]]


# ------------------------------------------------------------
# dim_cliente (con 2 casos SCD Tipo 2)
# ------------------------------------------------------------
NOMBRES = ["Sofia", "Mateo", "Valentina", "Benjamin", "Camila", "Thiago",
           "Martina", "Joaquin", "Julieta", "Lautaro", "Delfina", "Bautista"]
APELLIDOS = ["Gomez", "Fernandez", "Rodriguez", "Lopez", "Diaz", "Martinez",
             "Perez", "Sosa", "Romero", "Alvarez", "Torres", "Ruiz"]
SEGMENTOS = ["Nuevo", "Recurrente", "VIP"]
PROVINCIAS = [g[1] for g in GEO]


def gen_dim_cliente():
    filas = [[-1, -1, "Desconocido", "Desconocido", None, "Desconocido",
              "Desconocido", "1900-01-01", "9999-12-31", 1]]
    sk = 1
    cliente_ids = []
    N = 40
    for cid in range(1001, 1001 + N):
        nom = random.choice(NOMBRES)
        ape = random.choice(APELLIDOS)
        seg = random.choice(SEGMENTOS)
        prov = random.choice(PROVINCIAS)
        email = "%s.%s@mail.com" % (nom.lower(), ape.lower())
        cliente_ids.append(cid)
        # Dos clientes con historia SCD Tipo 2 (cambio de provincia)
        if cid in (1005, 1012):
            prov2 = random.choice([p for p in PROVINCIAS if p != prov])
            filas.append([sk, cid, nom, ape, email, seg, prov,
                          "2024-01-01", "2024-06-30", 0]); sk += 1
            filas.append([sk, cid, nom, ape, email, seg, prov2,
                          "2024-07-01", "9999-12-31", 1]); sk += 1
        else:
            filas.append([sk, cid, nom, ape, email, seg, prov,
                          "2024-01-01", "9999-12-31", 1]); sk += 1
    escribir("dim_cliente.csv",
             ["cliente_sk", "cliente_id", "nombre", "apellido", "email",
              "segmento", "provincia", "vig_desde", "vig_hasta", "es_actual"], filas)
    # devuelve solo las SK vigentes para asignar en la fact
    return [f[0] for f in filas[1:] if f[9] == 1]


# ------------------------------------------------------------
# dim_producto (jerarquia categoria > subcategoria)
# ------------------------------------------------------------
CATALOGO = [
    ("Notebook Lenovo IdeaPad", "Lenovo", "Notebooks", "Electronica", 850000),
    ("Smartphone Samsung A54", "Samsung", "Celulares", "Electronica", 520000),
    ("Auriculares JBL Tune", "JBL", "Audio", "Electronica", 95000),
    ("Smart TV LG 50", "LG", "Televisores", "Electronica", 680000),
    ("Cafetera Philips", "Philips", "Cocina", "Hogar", 145000),
    ("Aspiradora Electrolux", "Electrolux", "Limpieza", "Hogar", 210000),
    ("Juego de Sabanas King", "Palette", "Blanco", "Hogar", 78000),
    ("Zapatillas Nike Revolution", "Nike", "Calzado", "Indumentaria", 130000),
    ("Campera Adidas", "Adidas", "Abrigo", "Indumentaria", 165000),
    ("Remera Topper", "Topper", "Basicos", "Indumentaria", 32000),
    ("Bicicleta Venzo MTB", "Venzo", "Ciclismo", "Deportes", 480000),
    ("Pelota Penalty", "Penalty", "Futbol", "Deportes", 45000),
]


def gen_dim_producto():
    filas = [[-1, -1, "Desconocido", "Desconocido", "Desconocido", "Desconocido", 0]]
    sk = 1
    for pid, (nom, marca, sub, cat, precio) in enumerate(CATALOGO, start=2001):
        filas.append([sk, pid, nom, marca, sub, cat, precio]); sk += 1
    escribir("dim_producto.csv",
             ["producto_sk", "producto_id", "nombre_producto", "marca",
              "subcategoria", "categoria", "precio_lista"], filas)
    return [(f[0], f[6]) for f in filas[1:]]  # (sk, precio_lista)


# ------------------------------------------------------------
# dim_medio_pago
# ------------------------------------------------------------
def gen_dim_medio_pago():
    filas = [
        [-1, "Desconocido", 0],
        [1, "Tarjeta", 1],
        [2, "Tarjeta", 3],
        [3, "Tarjeta", 6],
        [4, "Transferencia", 1],
        [5, "Efectivo", 1],
    ]
    escribir("dim_medio_pago.csv", ["medio_pago_sk", "tipo", "cuotas"], filas)
    return [f[0] for f in filas[1:]]


# ------------------------------------------------------------
# fact_ventas (grano = linea de pedido)
# ------------------------------------------------------------
def gen_fact(fechas_sk, cli_sk, prod, geo_sk, mp_sk, n_lineas=2000):
    filas = []
    nro_pedido = 50000
    i = 0
    while i < n_lineas:
        nro_pedido += 1
        cliente = random.choice(cli_sk)
        geografia = random.choice(geo_sk)
        medio = random.choice(mp_sk)
        f_ped = random.choice(fechas_sk)
        # fecha de pago = pedido + 0..5 dias (role-playing distinto)
        f_pag = min(f_ped + random.randint(0, 5), max(fechas_sk))
        if f_pag not in fechas_sk:
            f_pag = f_ped
        # 1..3 lineas por pedido
        for _ in range(random.randint(1, 3)):
            if i >= n_lineas:
                break
            producto_sk, precio = random.choice(prod)
            cantidad = random.randint(1, 4)
            desc = round(precio * cantidad * random.choice([0, 0, 0.1, 0.15]), 2)
            total = round(precio * cantidad - desc, 2)
            filas.append([f_ped, f_pag, cliente, producto_sk, geografia, medio,
                          nro_pedido, cantidad, precio, desc, total])
            i += 1
    escribir("fact_ventas.csv",
             ["fecha_pedido_sk", "fecha_pago_sk", "cliente_sk", "producto_sk",
              "geografia_sk", "medio_pago_sk", "nro_pedido", "cantidad",
              "precio_unitario", "descuento", "importe_total"], filas)


# ------------------------------------------------------------
def main():
    print("Generando dataset e-commerce (esquema estrella)...")
    fechas = gen_dim_fecha()
    geo = gen_dim_geografia()
    cli = gen_dim_cliente()
    prod = gen_dim_producto()
    mp = gen_dim_medio_pago()
    gen_fact(fechas, cli, prod, geo, mp)
    print("Listo -> dataset/csv/")


if __name__ == "__main__":
    main()
