/**
 * Departamento Controller
 * API endpoints para gestión de departamentos/unidades
 *
 * @module Construction (MAI-002)
 * @prefix /api/v1/departamentos
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DepartamentoService, CreateDepartamentoDto, UpdateDepartamentoDto, SellDepartamentoDto } from '../services/departamento.service';

const router = Router();
const departamentoService = new DepartamentoService(null as any);

/**
 * GET /api/v1/departamentos
 * Lista todos los departamentos del tenant
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { nivelId, torreId, prototipoId, status, minPrice, maxPrice, search, page, limit } = req.query;

    const result = await departamentoService.findAll(
      { tenantId },
      {
        nivelId: nivelId as string,
        torreId: torreId as string,
        prototipoId: prototipoId as string,
        status: status as string,
        minPrice: minPrice ? Number(minPrice) : undefined,
        maxPrice: maxPrice ? Number(maxPrice) : undefined,
        search: search as string,
        page: page ? Number(page) : undefined,
        limit: limit ? Number(limit) : undefined,
      },
    );

    return res.json({
      success: true,
      data: result.data,
      total: result.total,
      page: result.page,
      limit: result.limit,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/departamentos/statistics
 * Estadísticas de departamentos
 */
router.get('/statistics', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { torreId } = req.query;
    const stats = await departamentoService.getStatistics({ tenantId }, torreId as string);

    return res.json({ success: true, data: stats });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/departamentos/available
 * Departamentos disponibles
 */
router.get('/available', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { torreId } = req.query;
    const data = await departamentoService.findAvailable({ tenantId }, torreId as string);

    return res.json({ success: true, data, count: data.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/departamentos/by-nivel/:nivelId
 * Departamentos por nivel
 */
router.get('/by-nivel/:nivelId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data = await departamentoService.findByNivel({ tenantId }, req.params.nivelId);
    return res.json({ success: true, data, count: data.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/departamentos/by-torre/:torreId
 * Departamentos por torre
 */
router.get('/by-torre/:torreId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data = await departamentoService.findByTorre({ tenantId }, req.params.torreId);
    return res.json({ success: true, data, count: data.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/departamentos/:id
 * Obtiene un departamento por ID
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const departamento = await departamentoService.findById({ tenantId }, req.params.id);
    if (!departamento) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, data: departamento });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/departamentos
 * Crea un nuevo departamento
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const dto: CreateDepartamentoDto = req.body;

    if (!dto.nivelId || !dto.code || !dto.unitNumber) {
      return res.status(400).json({ error: 'nivelId, code y unitNumber son requeridos' });
    }

    const departamento = await departamentoService.create({ tenantId, userId }, dto);
    return res.status(201).json({ success: true, data: departamento });
  } catch (error: any) {
    if (error.message?.includes('already exists')) {
      return res.status(409).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * PATCH /api/v1/departamentos/:id
 * Actualiza un departamento
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const dto: UpdateDepartamentoDto = req.body;

    const departamento = await departamentoService.update({ tenantId, userId }, req.params.id, dto);
    if (!departamento) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, data: departamento });
  } catch (error: any) {
    if (error.message?.includes('Cannot update')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/departamentos/:id/reserve
 * Reserva un departamento
 */
router.post('/:id/reserve', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const { buyerId } = req.body;

    if (!buyerId) {
      return res.status(400).json({ error: 'buyerId es requerido' });
    }

    const departamento = await departamentoService.reserve({ tenantId, userId }, req.params.id, buyerId);
    if (!departamento) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, data: departamento, message: 'Departamento reservado' });
  } catch (error: any) {
    if (error.message?.includes('not available')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/departamentos/:id/cancel-reservation
 * Cancela la reservación de un departamento
 */
router.post('/:id/cancel-reservation', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const departamento = await departamentoService.cancelReservation({ tenantId, userId }, req.params.id);

    if (!departamento) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, data: departamento, message: 'Reservación cancelada' });
  } catch (error: any) {
    if (error.message?.includes('not reserved')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/departamentos/:id/sell
 * Vende un departamento
 */
router.post('/:id/sell', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const dto: SellDepartamentoDto = req.body;

    if (!dto.buyerId || dto.priceFinal === undefined) {
      return res.status(400).json({ error: 'buyerId y priceFinal son requeridos' });
    }

    const departamento = await departamentoService.sell({ tenantId, userId }, req.params.id, dto);
    if (!departamento) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, data: departamento, message: 'Departamento vendido' });
  } catch (error: any) {
    if (error.message?.includes('not available')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/departamentos/:id/deliver
 * Marca un departamento como entregado
 */
router.post('/:id/deliver', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const { deliveryDate } = req.body;

    const departamento = await departamentoService.markDelivered(
      { tenantId, userId },
      req.params.id,
      deliveryDate ? new Date(deliveryDate) : undefined,
    );

    if (!departamento) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, data: departamento, message: 'Departamento entregado' });
  } catch (error: any) {
    if (error.message?.includes('must be sold')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * DELETE /api/v1/departamentos/:id
 * Elimina un departamento (soft delete)
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const userId = (req as any).user?.id;
    const deleted = await departamentoService.softDelete({ tenantId, userId }, req.params.id);

    if (!deleted) {
      return res.status(404).json({ error: 'Departamento no encontrado' });
    }

    return res.json({ success: true, message: 'Departamento eliminado' });
  } catch (error: any) {
    if (error.message?.includes('Cannot delete')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

export default router;
