/**
 * Product Attribute Controller
 * API endpoints para gestion de atributos de productos
 *
 * @module Products
 * @prefix /api/v1/products/attributes
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  ProductAttributeService,
  CreateProductAttributeDto,
  UpdateProductAttributeDto,
  UpdateAttributeValueDto
} from '../services/product-attribute.service';

const router = Router();
const attributeService = new ProductAttributeService();

/**
 * GET /api/v1/products/attributes
 * Lista todos los atributos 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 { isActive, search } = req.query;

    const attributes = await attributeService.findAll({
      tenantId,
      isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
      search: search as string,
    });

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

/**
 * GET /api/v1/products/attributes/:id
 * Obtiene un atributo 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 attribute = await attributeService.findById(req.params.id, tenantId);
    if (!attribute) {
      return res.status(404).json({ error: 'Atributo no encontrado' });
    }

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

/**
 * GET /api/v1/products/attributes/:id/values
 * Obtiene los valores de un atributo
 */
router.get('/:id/values', 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 attribute = await attributeService.findById(req.params.id, tenantId);
    if (!attribute) {
      return res.status(404).json({ error: 'Atributo no encontrado' });
    }

    const values = await attributeService.findValuesByAttribute(req.params.id);

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

/**
 * POST /api/v1/products/attributes
 * Crea un nuevo atributo
 */
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 { values, ...attributeData } = req.body;

    const data: CreateProductAttributeDto = {
      ...attributeData,
      tenantId,
      createdBy: (req as any).user?.id,
    };

    if (!data.code || !data.name) {
      return res.status(400).json({
        error: 'code y name son requeridos'
      });
    }

    const existing = await attributeService.findByCode(data.code, tenantId);
    if (existing) {
      return res.status(409).json({ error: 'Ya existe un atributo con ese codigo' });
    }

    let attribute;
    if (values && Array.isArray(values) && values.length > 0) {
      attribute = await attributeService.createWithValues(data, values);
    } else {
      attribute = await attributeService.create(data);
    }

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

/**
 * POST /api/v1/products/attributes/:id/values
 * Agrega valores a un atributo
 */
router.post('/:id/values', 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 attribute = await attributeService.findById(req.params.id, tenantId);
    if (!attribute) {
      return res.status(404).json({ error: 'Atributo no encontrado' });
    }

    const { values } = req.body;
    if (!values || !Array.isArray(values) || values.length === 0) {
      return res.status(400).json({ error: 'values array is required' });
    }

    const createdValues = await attributeService.addValues(req.params.id, values);

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

/**
 * POST /api/v1/products/attributes/:id/values/reorder
 * Reordena los valores de un atributo
 */
router.post('/:id/values/reorder', 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 attribute = await attributeService.findById(req.params.id, tenantId);
    if (!attribute) {
      return res.status(404).json({ error: 'Atributo no encontrado' });
    }

    const { valueIds } = req.body;
    if (!valueIds || !Array.isArray(valueIds)) {
      return res.status(400).json({ error: 'valueIds array is required' });
    }

    await attributeService.reorderValues(req.params.id, valueIds);

    return res.json({ success: true, message: 'Valores reordenados' });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/products/attributes/:id
 * Actualiza un atributo
 */
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 data: UpdateProductAttributeDto = {
      ...req.body,
      updatedBy: (req as any).user?.id,
    };

    if (data.code) {
      const existing = await attributeService.findByCode(data.code, tenantId);
      if (existing && existing.id !== req.params.id) {
        return res.status(409).json({ error: 'Ya existe un atributo con ese codigo' });
      }
    }

    const attribute = await attributeService.update(req.params.id, tenantId, data);
    if (!attribute) {
      return res.status(404).json({ error: 'Atributo no encontrado' });
    }

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

/**
 * PATCH /api/v1/products/attributes/values/:valueId
 * Actualiza un valor de atributo
 */
router.patch('/values/:valueId', 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: UpdateAttributeValueDto = req.body;
    const value = await attributeService.updateValue(req.params.valueId, data);

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

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

/**
 * DELETE /api/v1/products/attributes/:id
 * Elimina un atributo y todos sus valores
 */
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 deleted = await attributeService.delete(req.params.id, tenantId);
    if (!deleted) {
      return res.status(404).json({ error: 'Atributo no encontrado' });
    }

    return res.json({ success: true, message: 'Atributo eliminado' });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/products/attributes/values/:valueId
 * Elimina un valor de atributo
 */
router.delete('/values/:valueId', 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 deleted = await attributeService.deleteValue(req.params.valueId);
    if (!deleted) {
      return res.status(404).json({ error: 'Valor no encontrado' });
    }

    return res.json({ success: true, message: 'Valor eliminado' });
  } catch (error) {
    return next(error);
  }
});

export default router;
