import type { Request, Response, NextFunction } from 'express';
import { prisma } from '../config/database.js';
import { isGlobalAdmin } from '../utils/global-admin.js';

// Simple in-memory cache with TTL
const cache = new Map<string, { data: any; expires: number }>();

async function getCached<T>(key: string, ttlMs: number, fetcher: () => Promise<T>): Promise<T> {
  const entry = cache.get(key);
  if (entry && entry.expires > Date.now()) return entry.data;
  const data = await fetcher();
  cache.set(key, { data, expires: Date.now() + ttlMs });
  return data;
}

export function invalidateTenantCache(tenantId: string) {
  for (const key of cache.keys()) {
    if (key.includes(tenantId)) cache.delete(key);
  }
}

/**
 * Checks if tenant has an active subscription before allowing write operations
 */
export async function checkPlanLimits(req: Request, res: Response, next: NextFunction) {
  if (!req.user) return next();

  // Global admin impersonation bypasses subscription check
  if (req.headers['x-view-tenant'] && await isGlobalAdmin(req.user.tenantId, req.user.role)) {
    return next();
  }

  const subscription = await getCached(
    `sub:${req.user.tenantId}`,
    5 * 60 * 1000,
    () => prisma.subscription.findFirst({
      where: { tenantId: req.user!.tenantId },
      orderBy: { createdAt: 'desc' },
    })
  );

  const allowedStatuses = ['authorized', 'pending'];

  if (!subscription || !allowedStatuses.includes(subscription.status)) {
    // Allow GET requests even with inactive subscription (read-only access)
    if (req.method !== 'GET') {
      return res.status(403).json({
        message: 'Suscripción inactiva. Contacta soporte para reactivar.',
      });
    }
  }

  next();
}

/**
 * Checks if tenant has room for more CFDIs before allowing CFDI creation
 */
export async function checkCfdiLimit(req: Request, res: Response, next: NextFunction) {
  if (!req.user || !req.tenantPool) return next();

  const tenant = await getCached(
    `tenant:${req.user.tenantId}`,
    5 * 60 * 1000,
    () => prisma.tenant.findUnique({
      where: { id: req.user!.tenantId },
      select: { cfdiLimit: true },
    })
  );

  if (!tenant || tenant.cfdiLimit === -1) return next(); // unlimited

  const cfdiCount = await getCached(
    `cfdi-count:${req.user.tenantId}`,
    5 * 60 * 1000,
    async () => {
      const result = await req.tenantPool!.query('SELECT COUNT(*) FROM cfdis');
      return parseInt(result.rows[0].count);
    }
  );

  const newCount = Array.isArray(req.body) ? req.body.length : 1;
  if (cfdiCount + newCount > tenant.cfdiLimit) {
    return res.status(403).json({
      message: `Límite de CFDIs alcanzado (${cfdiCount}/${tenant.cfdiLimit}). Contacta soporte para upgrade.`,
    });
  }

  next();
}
