/**
 * api-key.ts
 *
 * Sistema de API Keys para acceso externo seguro (inspirado en OpenWA api-key.guard.ts).
 * Permite a sistemas externos (Zapier, n8n, CRM) llamar la API del bot usando
 * el header "X-API-Key" en lugar de la cookie de sesión del dashboard.
 *
 * Añade soporte para permisos/scopes (read/write) y rate limiting por minuto.
 */

import crypto from "node:crypto";
import { createApiKey, findApiKeyByHash, listApiKeys, deleteApiKey } from "./db";

/**
 * Estructura para el rate limiter en memoria
 */
const rateLimitMap = new Map<string, { count: number; resetAt: number }>();

/**
 * Genera una nueva API key, la almacena hasheada en SQLite, y retorna
 * el valor en texto plano (solo se muestra UNA vez al momento de creación).
 */
export function generateApiKey(
  label: string | null,
  scopes: string[] = ["read", "write"],
  rateLimit = 60
): { id: string; key: string; label: string | null } {
  const id = crypto.randomUUID();
  // Generar una key de 32 bytes aleatorios en formato hex (64 caracteres)
  const key = crypto.randomBytes(32).toString("hex");
  const keyHash = hashApiKey(key);
  createApiKey(id, keyHash, label, JSON.stringify(scopes), rateLimit);
  console.log(`[api-key] ✅ API Key generada: id=${id}, label="${label ?? "sin etiqueta"}", scopes=${JSON.stringify(scopes)}, rateLimit=${rateLimit}`);
  return { id, key, label };
}

/**
 * Verifica si una API key (en texto plano) es válida.
 * Compara el hash SHA-256 contra los hashes almacenados en la DB.
 * Mantenido por compatibilidad simple.
 */
export function validateApiKey(key: string): boolean {
  return validateApiKeyWithRequirements(key, "read").valid;
}

/**
 * Valida una API key y comprueba si tiene el scope necesario y no ha superado el rate limit.
 */
export function validateApiKeyWithRequirements(
  key: string,
  requiredScope: "read" | "write"
): { valid: boolean; error?: string; operator?: string } {
  if (!key || typeof key !== "string") {
    return { valid: false, error: "API Key ausente o inválida" };
  }

  try {
    const keyHash = hashApiKey(key);
    const found = findApiKeyByHash(keyHash);
    
    if (!found) {
      return { valid: false, error: "API Key no registrada" };
    }

    // 1. Validar Scope/Permisos
    let scopesList: string[] = ["read", "write"];
    try {
      scopesList = JSON.parse(found.scopes);
    } catch {}

    if (!scopesList.includes(requiredScope)) {
      return { 
        valid: false, 
        error: `Permiso insuficiente. Requiere ámbito '${requiredScope}'.` 
      };
    }

    // 2. Validar Rate Limit (por minuto)
    const now = Date.now();
    const limit = found.rate_limit || 60;
    const bucket = rateLimitMap.get(keyHash);

    if (!bucket || now > bucket.resetAt) {
      // Iniciar nuevo minuto
      rateLimitMap.set(keyHash, {
        count: 1,
        resetAt: now + 60000
      });
    } else {
      if (bucket.count >= limit) {
        const waitSecs = Math.ceil((bucket.resetAt - now) / 1000);
        return { 
          valid: false, 
          error: `Límite de velocidad excedido (${limit} peticiones/min). Intente de nuevo en ${waitSecs}s.` 
        };
      }
      bucket.count++;
    }

    const labelStr = found.label ? ` (${found.label})` : "";
    return { 
      valid: true, 
      operator: `api_key:${found.id}${labelStr}` 
    };
  } catch (err) {
    console.error("[api-key] Error validando API key:", err);
    return { valid: false, error: "Error interno de validación" };
  }
}

/**
 * Hashea una API key con SHA-256.
 */
function hashApiKey(key: string): string {
  return crypto.createHash("sha256").update(key).digest("hex");
}

export { listApiKeys, deleteApiKey };
