import type { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { prisma } from '../config/database.js';
import { hasPlatformRole } from '../utils/platform-admin.js';
import { auditLog } from '../utils/audit.js';
import { AppError } from '../middlewares/error.middleware.js';

const impersonateSchema = z.object({
  despachoId: z.string().uuid('ID de despacho inválido'),
  motivo: z.string().min(5, 'Motivo es obligatorio (mínimo 5 caracteres)'),
});

export async function startImpersonation(req: Request, res: Response, next: NextFunction) {
  try {
    if (!req.user?.userId) return next(new AppError(401, 'No autenticado'));

    const canImpersonate = await hasPlatformRole(req.user.userId, 'platform_admin') ||
                           await hasPlatformRole(req.user.userId, 'platform_ti') ||
                           await hasPlatformRole(req.user.userId, 'platform_support');
    if (!canImpersonate) return next(new AppError(403, 'No tienes permisos para impersonar'));

    const { despachoId, motivo } = impersonateSchema.parse(req.body);

    const tenant = await prisma.tenant.findUnique({
      where: { id: despachoId },
      select: { id: true, nombre: true, rfc: true, active: true },
    });
    if (!tenant) return next(new AppError(404, 'Despacho no encontrado'));
    if (!tenant.active) return next(new AppError(403, 'Despacho inactivo'));

    await auditLog({
      userId: req.user.userId,
      tenantId: despachoId,
      action: 'admin.impersonate_start',
      entityType: 'tenant',
      entityId: despachoId,
      metadata: {
        motivo,
        adminEmail: req.user.email,
        despachoNombre: tenant.nombre,
        despachoRfc: tenant.rfc,
        ip: req.ip,
        userAgent: req.headers['user-agent'],
      },
    });

    return res.json({
      despachoId: tenant.id,
      nombre: tenant.nombre,
      rfc: tenant.rfc,
      message: 'Impersonación iniciada. Usa el header X-View-Tenant para acceder.',
    });
  } catch (err: any) {
    if (err instanceof z.ZodError) return next(new AppError(400, err.errors[0].message));
    return next(err);
  }
}

export async function stopImpersonation(req: Request, res: Response, next: NextFunction) {
  try {
    if (!req.user?.userId) return next(new AppError(401, 'No autenticado'));

    const despachoId = req.body.despachoId as string | undefined;

    await auditLog({
      userId: req.user.userId,
      tenantId: despachoId || undefined,
      action: 'admin.impersonate_end',
      metadata: {
        adminEmail: req.user.email,
        ip: req.ip,
      },
    });

    return res.json({ message: 'Impersonación finalizada' });
  } catch (err) { return next(err); }
}
