// services/app/src/index.js
// ------------------------------------------------------------
// SuiteCoffee — Servicio APP (UI + APIs negocio)
// - ESM (Node >=18)
// - Vistas EJS en ./views (dashboard.ejs, comandas.ejs, etc.)
// - Sesión compartida con AUTH (cookie: sc.sid, Redis)
// - Monta routes.legacy.js con requireAuth + withTenant
// ------------------------------------------------------------

import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import morgan from 'morgan';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import session from 'express-session';
import expressLayouts from 'express-ejs-layouts';
import { createClient as createRedisClient } from 'redis';
import * as connectRedis from 'connect-redis';
import { Pool } from 'pg';

// -----------------------------------------------------------------------------
// Utilidades base
// -----------------------------------------------------------------------------
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const RedisStore = connectRedis.default || connectRedis.RedisStore;

const qi = (ident) => `"${String(ident).replace(/"/g, '""')}"`;
const CLEAN_HEX = (s) => (String(s || '').toLowerCase().replace(/[^0-9a-f]/g, '') || null);
const REQUIRED = (...keys) => {
  const miss = keys.filter((k) => !process.env[k]);
  if (miss.length) {
    console.warn(`⚠ Faltan variables de entorno: ${miss.join(', ')}`);
  }
};

// -----------------------------------------------------------------------------
// Validación de entorno mínimo (ajusta nombres si difieren)
// -----------------------------------------------------------------------------
REQUIRED(
  // Sesión
  'SESSION_SECRET', 'REDIS_URL',
  // DB principal
  'DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS',
  // DB de tenants
  'TENANTS_HOST', 'TENANTS_DB', 'TENANTS_USER', 'TENANTS_PASS'
);

// -----------------------------------------------------------------------------
// Pools de PostgreSQL
// -----------------------------------------------------------------------------
const mainPool = new Pool({
  host: process.env.DB_HOST,
  port: Number(process.env.DB_PORT || 5432),
  database: process.env.DB_NAME,
  user: process.env.DB_USER,
  password: process.env.DB_PASS,
  max: 10,
  idleTimeoutMillis: 30_000,
});

const tenantsPool = new Pool({
  host: process.env.TENANTS_HOST,
  port: Number(process.env.TENANTS_PORT || 5432),
  database: process.env.TENANTS_DB,
  user: process.env.TENANTS_USER,
  password: process.env.TENANTS_PASS,
  max: 10,
  idleTimeoutMillis: 30_000,
});

// Autotest (no rompe si falla; sólo loguea)
(async () => {
  try {
    const c = await mainPool.connect();
    const r = await c.query('SELECT NOW() now');
    console.log('[APP] DB principal OK. Hora:', r.rows[0].now);
    c.release();
  } catch (e) {
    console.error('[APP] Error al conectar DB principal:', e.message);
  }
  try {
    const c = await tenantsPool.connect();
    const r = await c.query('SELECT NOW() now');
    console.log('[APP] DB tenants OK. Hora:', r.rows[0].now);
    c.release();
  } catch (e) {
    console.error('[APP] Error al conectar DB tenants:', e.message);
  }
})();

// -----------------------------------------------------------------------------
// Express + EJS
// -----------------------------------------------------------------------------
const app = express();
app.set('trust proxy', 1);

// Views EJS en ./views
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(expressLayouts);
app.set("layout", "layouts/main");

// Estáticos (si tenés carpeta public/, assets, etc.)
app.use('/public', express.static(path.join(__dirname, 'public')));

// Middlewares básicos
app.use(morgan('dev'));
app.use(cors({ origin: true, credentials: true }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// ----------------------------------------------------------
// Middleware para datos globales
// ----------------------------------------------------------
app.use((req, res, next) => {
  res.locals.currentPath = req.path;
  res.locals.pageTitle = "SuiteCoffee"; 
  res.locals.pageId = "";               
  next();
});


// -----------------------------------------------------------------------------
// Sesión (Redis) — misma cookie que AUTH
// -----------------------------------------------------------------------------
const SESSION_COOKIE_NAME = 'sc.sid';
const redis = createRedisClient({ url: process.env.REDIS_URL });
await redis.connect().catch((e) => console.error('[APP] Redis session error:', e.message));

app.use(
  session({
    name: SESSION_COOKIE_NAME,
    store: new RedisStore({ client: redis, prefix: 'sess:' }),
    secret: process.env.SESSION_SECRET || 'change-me',
    resave: false,
    saveUninitialized: false,
    cookie: {
      httpOnly: true,
      sameSite: 'lax',
      secure: process.env.NODE_ENV === 'production',
      // domain: 'suitecoffee.mateosaldain.uy', // (opcional) si lo necesitás
    },
  })
);

// Exponer usuario a las vistas
app.use((req, res, next) => {
  res.locals.user = req.session?.user || null;
  next();
});

// -----------------------------------------------------------------------------
// Middlewares de Auth/Tenant para routes.legacy.js
// -----------------------------------------------------------------------------
function requireAuth(req, res, next) {
  if (!req.session?.user) {
    // Si querés devolver 401 en lugar de redirigir, cambia esta línea
    return res.redirect('/auth/login');
  }
  next();
}

// Abre un client al DB de tenants y fija search_path al esquema del usuario
async function withTenant(req, res, next) {
  try {
    const hex = CLEAN_HEX(req.session?.user?.tenant_uuid);
    if (!hex) return res.status(400).json({ error: 'tenant-missing' });

    const schema = `schema_tenant_${hex}`;
    const client = await tenantsPool.connect();

    // Fijar search_path para que las consultas apunten al esquema del tenant
    await client.query(`SET SESSION search_path TO ${qi(schema)}, public`);

    // Hacemos el client accesible para los handlers de routes.legacy.js
    req.pg = client;

    // Liberar el client al finalizar la respuesta
    const release = () => {
      try { client.release(); } catch {}
    };
    res.on('finish', release);
    res.on('close', release);

    next();
  } catch (e) {
    next(e);
  }
}

// No-op (compatibilidad con el archivo legacy si lo pasa al final)
function done(_req, _res, next) { return next && next(); }

// -----------------------------------------------------------------------------
// Home / Landing
// -----------------------------------------------------------------------------
app.get('/', (req, res) => {
  if (req.session?.user) {
    return res.redirect('/comandas'); // ya logueado → dashboard
  }
  return res.render('login', { pageTitle: 'Iniciar sesión' });
});

// Página para definir contraseña (el form envía al servicio AUTH)
app.get('/set-password', (req, res) => {
  const pp = req.session?.pendingPassword;
  if (!pp) return req.session?.user ? res.redirect('/comandas') : res.redirect('/auth/login');

  res.type('html').send(`
    <!doctype html><meta charset="utf-8">
    <title>SuiteCoffee · Definir contraseña</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
    <div class="container py-5" style="max-width:520px;">
      <h2 class="mb-4">Definir contraseña</h2>
      <form method="post" action="/auth/password/set" class="vstack gap-3">
        <input class="form-control" type="password" name="password" placeholder="Nueva contraseña" minlength="8" required>
        <input class="form-control" type="password" name="password2" placeholder="Repetí la contraseña" minlength="8" required>
        <button class="btn btn-primary" type="submit">Guardar y continuar</button>
        <small class="text-muted">Luego te redirigiremos a iniciar sesión por SSO.</small>
      </form>
    </div>
  `);
});

// -----------------------------------------------------------------------------
// Montar rutas legacy (render de EJS y APIs de negocio)
// -----------------------------------------------------------------------------
const legacy = await import('./routes.legacy.js');
legacy.default(app, {
  requireAuth,
  withTenant,
  done,
  mainPool,
  tenantsPool,
  express,
});

// -----------------------------------------------------------------------------
// Health + 404 + errores
// -----------------------------------------------------------------------------
app.get('/health', (_req, res) => res.status(200).json({ status: 'ok', service: 'app' }));

app.use((req, res) => res.status(404).json({ error: 'not-found', path: req.originalUrl }));

app.use((err, _req, res, _next) => {
  console.error('[APP] Error:', err);
  if (res.headersSent) return;
  res.status(500).json({ error: 'internal-error', detail: err?.message || String(err) });
});

// -----------------------------------------------------------------------------
// Arranque
// -----------------------------------------------------------------------------
const PORT = Number(process.env.PORT || process.env.APP_LOCAL_PORT || 3030);
app.listen(PORT, () => {
  console.log(`[APP] SuiteCoffee corriendo en http://localhost:${PORT}`);
});
