import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import * as tenantsService from '../services/tenants.service.js';
import { AppError } from '../middlewares/error.middleware.js';
import { isGlobalAdmin } from '../utils/global-admin.js';
import { hasAnyPlatformRole } from '../utils/platform-admin.js';
import { isOwnerSomewhere } from '../utils/memberships.js';

async function requireGlobalAdmin(req: Request): Promise<void> {
  if (!(await isGlobalAdmin(req.user!.tenantId, req.user!.role, req.user!.userId))) {
    throw new AppError(403, 'Solo el administrador global puede gestionar clientes');
  }
}

export async function getAllTenants(req: Request, res: Response, next: NextFunction) {
  try {
    // Admin global, TI y Vendedor pueden ver el listado completo de tenants.
    // Vendedor lo necesita para enviar invitaciones de trial.
    const canList = await hasAnyPlatformRole(req.user!.userId, 'platform_admin', 'platform_ti', 'platform_sales');
    if (!canList) {
      // Evita 403 en consola del frontend cuando componentes sin-gate hacen polling
      res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
      return res.json([]);
    }

    const tenants = await tenantsService.getAllTenants();
    res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');
    res.json(tenants);
  } catch (error) {
    next(error);
  }
}

export async function getTenant(req: Request, res: Response, next: NextFunction) {
  try {
    const isAdmin = await isGlobalAdmin(req.user!.tenantId, req.user!.role, req.user!.userId);
    if (!isAdmin) {
      return res.status(404).json({ message: 'Cliente no encontrado' });
    }

    const tenant = await tenantsService.getTenantById(String(req.params.id));
    if (!tenant) {
      throw new AppError(404, 'Cliente no encontrado');
    }

    res.json(tenant);
  } catch (error) {
    next(error);
  }
}

export async function createTenant(req: Request, res: Response, next: NextFunction) {
  try {
    await requireGlobalAdmin(req);

    const { nombre, rfc, plan, adminEmail, adminNombre, amount, firstPaymentDueAt, verticalProfile, codigoPostal } = req.body;

    if (!nombre || !rfc || !adminEmail || !adminNombre) {
      throw new AppError(400, 'Nombre, RFC, adminEmail y adminNombre son requeridos');
    }

    const result = await tenantsService.createTenant({
      nombre,
      rfc,
      plan,
      adminEmail,
      adminNombre,
      amount: amount || 0,
      firstPaymentDueAt: firstPaymentDueAt || null,
      verticalProfile: verticalProfile || 'CONTABLE',
      codigoPostal,
    });

    res.status(201).json(result);
  } catch (error) {
    next(error);
  }
}

export async function updateTenant(req: Request, res: Response, next: NextFunction) {
  try {
    await requireGlobalAdmin(req);

    const id = String(req.params.id);
    const { nombre, rfc, plan, active, amount, firstPaymentDueAt } = req.body;

    const tenant = await tenantsService.updateTenant(id, {
      nombre,
      rfc,
      plan,
      active,
      amount,
      firstPaymentDueAt: firstPaymentDueAt || null,
    });

    res.json(tenant);
  } catch (error) {
    next(error);
  }
}

export async function deleteTenant(req: Request, res: Response, next: NextFunction) {
  try {
    await requireGlobalAdmin(req);

    await tenantsService.deleteTenant(String(req.params.id));
    res.status(204).send();
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Self-serve (multi-tenant memberships)
// ============================================================================

/**
 * Lista detallada de empresas del caller con estado de suscripción. Usado por
 * `/mis-empresas`. A diferencia de `/auth/me`, incluye datos de subscription
 * (status, currentPeriodEnd, pendingPlan, etc.).
 */
export async function getMyTenants(req: Request, res: Response, next: NextFunction) {
  try {
    const data = await tenantsService.getMyTenantsDetailed(req.user!.userId);
    res.json(data);
  } catch (error) { next(error); }
}

const addTenantSchema = z.object({
  nombre: z.string().min(2, 'Nombre de empresa requerido'),
  rfc: z.string().min(12).max(13, 'RFC inválido'),
  plan: z.enum(['mi_empresa', 'mi_empresa_plus', 'business_control', 'business_cloud']).optional(),
});

/**
 * Agrega una empresa (tenant nuevo) bajo el user autenticado. El caller se
 * vuelve owner automáticamente vía TenantMembership.
 */
export async function addMyTenant(req: Request, res: Response, next: NextFunction) {
  try {
    const data = addTenantSchema.parse(req.body);
    // Gate: solo users que son owner en al menos un tenant pueden agregar
    // un RFC adicional. Un contador invitado a una empresa ajena no puede.
    if (!(await isOwnerSomewhere(req.user!.userId))) {
      throw new AppError(403, 'Solo los dueños pueden registrar empresas adicionales.');
    }
    const result = await tenantsService.addTenantToOwner({
      userId: req.user!.userId,
      nombre: data.nombre,
      rfc: data.rfc,
      plan: data.plan,
    });
    res.status(201).json({ tenant: result.tenant });
  } catch (error) {
    if (error instanceof z.ZodError) return next(new AppError(400, error.errors[0].message));
    if (error instanceof Error && error.message.includes('RFC')) {
      return next(new AppError(400, error.message));
    }
    next(error);
  }
}
