import type { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import * as planService from '../services/plan-catalogo.service.js';
import { prisma } from '../config/database.js';
import { invalidateDespachoPlanCache } from '../services/plan-catalogo.service.js';
import { canEditPrices } from '../utils/platform-admin.js';
import { AppError } from '../middlewares/error.middleware.js';

export async function getPlans(req: Request, res: Response, next: NextFunction) {
  try {
    const vertical = req.query.vertical as string | undefined;
    const plans = await planService.listPlans(vertical);
    return res.json({ data: plans });
  } catch (err) { return next(err); }
}

export async function getAddons(req: Request, res: Response, next: NextFunction) {
  try {
    const vertical = req.query.vertical as string | undefined;
    const addons = await planService.listAddons(vertical);
    return res.json({ data: addons });
  } catch (err) { return next(err); }
}

export async function getPlan(req: Request, res: Response, next: NextFunction) {
  try {
    const plan = await planService.getPlanByCodename(String(req.params.codename));
    if (!plan) return res.status(404).json({ message: 'Plan no encontrado' });
    return res.json(plan);
  } catch (err) { return next(err); }
}

// ============================================================================
// Catálogo despacho — limits + precios editables por admin global
// ============================================================================

/** GET /api/planes/despacho — devuelve los 6 planes con limits + precios. */
export async function listDespachoCatalogo(_req: Request, res: Response, next: NextFunction) {
  try {
    const plans = await planService.getAllDespachoPlanLimits();
    return res.json({ data: plans });
  } catch (err) { return next(err); }
}

const updateSchema = z.object({
  nombre: z.string().min(1).max(50).optional(),
  monthly: z.number().nullable().optional(),
  firstYear: z.number().nullable().optional(),
  renewal: z.number().nullable().optional(),
  permiteMonthly: z.boolean().optional(),
  maxRfcs: z.number().int().optional(),
  maxUsers: z.number().int().optional(),
  timbresIncluidosMes: z.number().int().nonnegative().optional(),
  dbMode: z.enum(['BYO', 'MANAGED']).optional(),
  permiteServidorBackup: z.boolean().optional(),
  permiteSatIncremental: z.boolean().optional(),
});

/** PATCH /api/planes/despacho/:plan — actualiza precios/limits. Solo admin con canEditPrices. */
export async function updateDespachoCatalogo(req: Request, res: Response, next: NextFunction) {
  try {
    if (!req.user || !(await canEditPrices(req.user.userId))) {
      throw new AppError(403, 'Solo admin global puede editar el catálogo');
    }
    const plan = String(req.params.plan);
    const data = updateSchema.parse(req.body);

    const existing = await prisma.despachoPlanPrice.findUnique({ where: { plan } });
    if (!existing) throw new AppError(404, `Plan '${plan}' no encontrado`);

    const updated = await prisma.despachoPlanPrice.update({ where: { plan }, data });
    invalidateDespachoPlanCache();

    return res.json({
      plan: updated.plan,
      nombre: updated.nombre,
      monthly: updated.monthly !== null ? Number(updated.monthly) : null,
      firstYear: updated.firstYear !== null ? Number(updated.firstYear) : null,
      renewal: updated.renewal !== null ? Number(updated.renewal) : null,
      permiteMonthly: updated.permiteMonthly,
      maxRfcs: updated.maxRfcs,
      maxUsers: updated.maxUsers,
      timbresIncluidosMes: updated.timbresIncluidosMes,
      dbMode: updated.dbMode,
      permiteServidorBackup: updated.permiteServidorBackup,
      permiteSatIncremental: updated.permiteSatIncremental,
    });
  } catch (err) {
    if (err instanceof z.ZodError) return next(new AppError(400, err.errors[0].message));
    return next(err);
  }
}
