# Adaptación: Python → Node.js/TypeScript

## Comparación de Enfoques

| Aspecto | Python (Original) | Node.js (Nueva) |
|--------|------------------|-----------------|
| Framework | Pandas + Selenium | Next.js API + Puppeteer |
| Automatización | Excel + Email | Base de datos + API |
| Ejecución | Script manual | Cron job automático |
| Frecuencia | Manual | Cada 2-3 días |
| Escalabilidad | Limitada (archivo local) | Distribuida (BD) |
| Seguridad | Ejecuta como usuario | Simula usuario (anti-bot) |

---

## Mapeo de Funcionalidad

### Python → Node.js

```
Código Python                    →  Código Node.js
─────────────────────────────────────────────────────
undetected_chromedriver          →  Puppeteer + stealth mode
ThreadPoolExecutor(max_workers=3) →  Sequential processing (2-3 sec delay)
pd.DataFrame()                   →  Database queries (container_tracking_history)
Excel Writer                     →  PostgreSQL storage
Email (win32.Dispatch)           →  (No emails, data en BD es el source of truth)
formatear_eta_unificada()        →  formatETA() function
scrap_[naviera]()                →  scrap[Carrier]() async functions
```

---

## Cambios Clave en Lógica

### 1. Anti-Detección

**Python:**
```python
driver = uc.Chrome(options=options)
options.add_argument("--disable-blink-features=AutomationControlled")
```

**Node.js:**
```typescript
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(navigator, "webdriver", {
    get: () => false,
  });
});
```

### 2. Espera de Elementos

**Python:**
```python
wait = WebDriverWait(driver, 30)
inp = wait.until(EC.presence_of_element_located((By.ID, "trackingNumber")))
```

**Node.js:**
```typescript
await page.waitForSelector("#trackingNumber", { timeout: 30000 });
```

### 3. Extracción de Texto

**Python:**
```python
eta = get_text_by_js(driver, 'xpath', sel_fecha)
```

**Node.js:**
```typescript
const eta = await page.evaluate(() => {
  const el = document.evaluate(xpath, document, null, 
    XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  return el?.textContent?.trim() || null;
});
```

### 4. Formato de Fecha

**Python:**
```python
def formatear_eta_unificada(row):
    eta_str = str(row['ETA']).strip()
    if "no encontrado" in eta_str.lower():
        return None
    # ... múltiples conversiones por naviera
    return datetime.strptime(...).strftime("%d/%m/%Y")
```

**Node.js:**
```typescript
function formatETA(etaString: string, carrier: string): string | null {
  if (!etaString || etaString.toLowerCase().includes("no encontrado")) {
    return null;
  }
  // ... conversiones por naviera
  return date.toISOString().split("T")[0];  // YYYY-MM-DD
}
```

### 5. Persistencia de Datos

**Python:**
```python
# Guarda en Excel archivo local
df_res.to_excel(path_abs, index=False)
# Envía por email
mail.Attachments.Add(path_abs)
```

**Node.js:**
```typescript
// Guarda en BD, siempre disponible
await pool.query(
  `INSERT INTO container_tracking_history 
   (container_shipment_id, carrier, eta_scraped, scrape_status)
   VALUES ($1, $2, $3, $4)`
);
// NO sobrescribe si falla:
if (status === "success" && etaFormatted) {
  await pool.query(
    `UPDATE container_shipment SET eta = $1 WHERE id = $2`,
    [etaFormatted, containerId]
  );
}
```

---

## Ventajas de la Nueva Solución

✅ **Automático**: Cron job sin intervención  
✅ **Escalable**: Procesa múltiples contenedores en paralelo  
✅ **Seguro**: No sobrescribe datos si falla  
✅ **Auditable**: Histórico completo de intentos  
✅ **Integrado**: Vive dentro de tu aplicación Next.js  
✅ **API-first**: Accesible programáticamente  
✅ **Sin dependencias externas**: No requiere Excel, Outlook, etc  

---

## Migración de Datos

Si tenías resultados en Excel, puedes importar manualmente:

```sql
INSERT INTO container_shipment (
  container_number, carrier, eta, created_at
)
SELECT 
  container_number, 
  naviera, 
  to_date(eta_formateada, 'DD/MM/YYYY'),
  NOW()
FROM your_import_table
WHERE container_number IS NOT NULL;
```

---

## Ejecución Comparativa

### Python (Original)
```
Paso 1: Abrir Excel
Paso 2: Ejecutar script Python
Paso 3: Esperar 30-60 minutos
Paso 4: Abre browser para ver web
Paso 5: Envía email con resultados
Paso 6: Guardar Excel en drive
```

### Node.js (Nueva)
```
Cron automático cada 2 horas:
  1. Consulta BD: contenedores sin actualizar
  2. Para cada uno: navega web, extrae ETA
  3. Guarda en BD (automáticamente)
  4. ✓ Listo - datos accesibles por API
```

---

## Performance

| Métrica | Python | Node.js |
|---------|--------|---------|
| Tiempo por contenedor | 30-45s | 15-30s |
| Memory footprint | ~200MB | ~100MB |
| Escalabilidad | 1 instancia | Distribuible |
| Overhead manual | Alto | Bajo (cron automático) |

---

## Cambios en Selectores

Si una naviera cambia su HTML, actualiza los XPaths en `src/lib/shipping-scraper.ts`:

```typescript
// Buscar en DevTools (F12) el elemento y copiar XPath:
// Right click → Copy → Copy XPath
const newXPath = "//div[contains(@class, 'eta')]//span";
const eta = await page.evaluate(() => {
  const el = document.evaluate(newXPath, document, null, 
    XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  return el?.textContent?.trim() || null;
});
```

---

## Testing

### Python Original
```bash
python scraper.py
# Abre browser, navega webs, genera Excel
```

### Node.js Nuevo
```bash
# Test local sin BD
npx tsx scripts/test-eta-scraper.ts

# Test con BD
curl -X POST http://localhost:3000/api/admin/eta-scraper \
  -H "Authorization: Bearer test-key" \
  -H "Content-Type: application/json"
```

---

## Compatibilidad

- Puppeteer soporta Chrome/Chromium/Brave
- Node.js 18+ (para async/await)
- PostgreSQL 12+ (para las funciones JSON nuevas)

---

## FAQ

**¿Qué pasa con el código Python?**
Ya no lo necesitas, la lógica está integrada en Node.js.

**¿Puedo usar ambos en paralelo?**
Sí, pero pueden generar conflictos de datos. Recomendamos una cosa u otra.

**¿Necesito mantener el archivo Excel?**
No, la BD es el fuente de verdad ahora.

**¿Los emails?**
Removidos. Los datos están en la BD, accesibles por API/Dashboard.

**¿Performance?**
Mejor: Puppeteer es más rápido que Selenium, y el procesamiento es distribuido.
