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

export async function getCatalogo(req: Request, res: Response, next: NextFunction) {
  try {
    return res.json({ data: obligacionesService.getCatalogo() });
  } catch (err) { return next(err); }
}

export async function getObligaciones(req: Request, res: Response, next: NextFunction) {
  try {
    const contribuyenteId = String(req.params.id);
    const rows = await obligacionesService.getObligaciones(req.tenantPool!, contribuyenteId);
    return res.json({ data: rows });
  } catch (err) { return next(err); }
}

export async function initRecomendaciones(req: Request, res: Response, next: NextFunction) {
  try {
    const contribuyenteId = String(req.params.id);
    const { rfc, regimenes, tieneNomina } = req.body;
    if (!rfc) return next(new AppError(400, 'rfc requerido'));
    const count = await obligacionesService.initRecomendaciones(
      req.tenantPool!, contribuyenteId, rfc, regimenes || [], tieneNomina ?? false
    );
    return res.json({ message: `${count} obligaciones recomendadas agregadas`, count });
  } catch (err) { return next(err); }
}

export async function addObligacion(req: Request, res: Response, next: NextFunction) {
  try {
    const contribuyenteId = String(req.params.id);
    const schema = z.object({
      catalogoId: z.string().optional(),
      nombre: z.string().min(2),
      fundamento: z.string().optional(),
      frecuencia: z.string().optional(),
      fechaLimite: z.string().optional(),
      categoria: z.string().optional(),
    });
    const data = schema.parse(req.body);
    const row = await obligacionesService.addObligacion(req.tenantPool!, contribuyenteId, data);
    return res.status(201).json(row);
  } catch (err: any) {
    if (err instanceof z.ZodError) return next(new AppError(400, err.errors[0].message));
    return next(err);
  }
}

export async function removeObligacion(req: Request, res: Response, next: NextFunction) {
  try {
    const ok = await obligacionesService.removeObligacion(req.tenantPool!, String(req.params.obligacionId));
    if (!ok) return next(new AppError(404, 'Obligación no encontrada'));
    return res.json({ message: 'Obligación desactivada' });
  } catch (err) { return next(err); }
}

export async function restoreObligacion(req: Request, res: Response, next: NextFunction) {
  try {
    const ok = await obligacionesService.restoreObligacion(req.tenantPool!, String(req.params.obligacionId));
    if (!ok) return next(new AppError(404, 'Obligación no encontrada'));
    return res.json({ message: 'Obligación restaurada' });
  } catch (err) { return next(err); }
}

export async function completeObligacion(req: Request, res: Response, next: NextFunction) {
  try {
    const periodo = req.body.periodo || new Date().toISOString().substring(0, 7);
    const ok = await obligacionesService.completeObligacion(req.tenantPool!, String(req.params.obligacionId), req.user!.userId, periodo);
    if (!ok) return next(new AppError(404, 'Obligación no encontrada'));
    return res.json({ message: 'Obligación marcada como completada' });
  } catch (err) { return next(err); }
}

export async function uncompleteObligacion(req: Request, res: Response, next: NextFunction) {
  try {
    const ok = await obligacionesService.uncompleteObligacion(req.tenantPool!, String(req.params.obligacionId));
    if (!ok) return next(new AppError(404, 'Obligación no encontrada'));
    return res.json({ message: 'Obligación desmarcada' });
  } catch (err) { return next(err); }
}

export async function getObligacionesPorPeriodo(req: Request, res: Response, next: NextFunction) {
  try {
    const contribuyenteId = String(req.params.id);
    const periodo = (req.query.periodo as string) || new Date().toISOString().substring(0, 7);
    const incluirAtrasados = req.query.atrasados !== 'false';
    const rows = await obligacionesService.getObligacionesPorPeriodo(req.tenantPool!, contribuyenteId, periodo, incluirAtrasados);
    return res.json({ data: rows, periodo });
  } catch (err) { return next(err); }
}

export async function completePeriodo(req: Request, res: Response, next: NextFunction) {
  try {
    const { periodo, notas } = req.body;
    if (!periodo) return next(new AppError(400, 'periodo requerido (YYYY-MM)'));
    await obligacionesService.completePeriodo(req.tenantPool!, String(req.params.obligacionId), periodo, req.user!.userId, notas);
    return res.json({ message: 'Obligación completada para el periodo' });
  } catch (err) { return next(err); }
}

export async function uncompletePeriodo(req: Request, res: Response, next: NextFunction) {
  try {
    const periodo = req.body.periodo || req.query.periodo;
    if (!periodo) return next(new AppError(400, 'periodo requerido'));
    await obligacionesService.uncompletePeriodo(req.tenantPool!, String(req.params.obligacionId), periodo as string);
    return res.json({ message: 'Completación removida' });
  } catch (err) { return next(err); }
}
