import type { Request, Response, NextFunction } from 'express';
import { hasFeature, hasDespachoFeature, type Plan, type DespachoPlan } from '@horux/shared';
import { prisma } from '../config/database.js';

const planCache = new Map<string, { plan: string; expires: number }>();

// Planes de la vertical despacho (tienen su propio catálogo con distintos
// features). Se resuelven vía `hasDespachoFeature`; el resto usa el
// catálogo Horux 360 vía `hasFeature`.
const DESPACHO_PLAN_NAMES = new Set(['trial', 'business_control', 'business_cloud']);

/**
 * Middleware factory that gates routes based on tenant plan features.
 * Usage: requireFeature('reportes') — blocks access if tenant's plan lacks the feature.
 */
export function requireFeature(feature: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    if (!req.user) return res.status(401).json({ message: 'No autenticado' });

    let plan: string;
    const cached = planCache.get(req.user.tenantId);
    if (cached && cached.expires > Date.now()) {
      plan = cached.plan;
    } else {
      const tenant = await prisma.tenant.findUnique({
        where: { id: req.user.tenantId },
        select: { plan: true },
      });
      if (!tenant) return res.status(404).json({ message: 'Tenant no encontrado' });
      plan = tenant.plan;
      planCache.set(req.user.tenantId, { plan, expires: Date.now() + 5 * 60 * 1000 });
    }

    // Resolver catálogo según la vertical del plan. Un plan desconocido
    // (ni Horux 360 ni despacho) se rechaza con 403 en vez de 500 como
    // defense-in-depth.
    const allowed = DESPACHO_PLAN_NAMES.has(plan)
      ? hasDespachoFeature(plan as DespachoPlan, feature)
      : hasFeature(plan as Plan, feature);

    if (!allowed) {
      return res.status(403).json({
        message: 'Tu plan no incluye esta función. Contacta soporte para upgrade.',
      });
    }

    next();
  };
}
