import type { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { AppError } from '../middlewares/error.middleware.js';
import * as activosFijosService from '../services/activos-fijos.service.js';

function effectiveTenantId(req: Request): string {
  return req.viewingTenantId || req.user!.tenantId;
}

const listSchema = z.object({
  año: z.string().regex(/^\d{4}$/),
  mes: z.string().regex(/^\d{1,2}$/),
  contribuyenteId: z.string().uuid().optional(),
  estado: z.enum(['todos', 'activos', 'baja', 'agotados']).optional(),
});

export async function list(req: Request, res: Response, next: NextFunction) {
  try {
    const q = listSchema.parse(req.query);
    const data = await activosFijosService.listActivosFijos(
      req.tenantPool!,
      effectiveTenantId(req),
      parseInt(q.año, 10),
      parseInt(q.mes, 10),
      q.contribuyenteId ?? null,
      q.estado,
    );
    res.json(data);
  } catch (error) {
    if (error instanceof z.ZodError) return next(new AppError(400, error.errors[0].message));
    next(error);
  }
}

const bajaSchema = z.object({
  fechaBaja: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
  motivo: z.enum(['venta', 'desecho', 'otro']),
  comentario: z.string().max(2000).nullable().optional(),
});

export async function darDeBaja(req: Request, res: Response, next: NextFunction) {
  try {
    const cfdiId = parseInt(String(req.params.cfdiId), 10);
    if (isNaN(cfdiId)) return next(new AppError(400, 'cfdiId inválido'));
    const data = bajaSchema.parse(req.body);
    await activosFijosService.darDeBaja(
      req.tenantPool!,
      cfdiId,
      data.fechaBaja,
      data.motivo,
      req.user!.userId,
      data.comentario ?? null,
    );
    res.status(201).json({ ok: true });
  } catch (error) {
    if (error instanceof z.ZodError) return next(new AppError(400, error.errors[0].message));
    next(error);
  }
}

const usosExcluidosSchema = z.object({
  contribuyenteId: z.string().uuid(),
  usos: z.array(z.string().regex(/^I0[1-8]$/)),
});

export async function setUsosExcluidos(req: Request, res: Response, next: NextFunction) {
  try {
    const { contribuyenteId, usos } = usosExcluidosSchema.parse(req.body);
    const saved = await activosFijosService.setUsosExcluidos(req.tenantPool!, contribuyenteId, usos);
    res.json({ usosExcluidos: saved });
  } catch (error) {
    if (error instanceof z.ZodError) return next(new AppError(400, error.errors[0].message));
    next(error);
  }
}

export async function revertirBaja(req: Request, res: Response, next: NextFunction) {
  try {
    const cfdiId = parseInt(String(req.params.cfdiId), 10);
    if (isNaN(cfdiId)) return next(new AppError(400, 'cfdiId inválido'));
    const ok = await activosFijosService.revertirBaja(req.tenantPool!, cfdiId);
    if (!ok) return next(new AppError(404, 'Activo no estaba dado de baja'));
    res.status(204).send();
  } catch (error) {
    next(error);
  }
}
