import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { currenciesService, CreateCurrencyDto, UpdateCurrencyDto } from './currencies.service.js';
import { countriesService } from './countries.service.js';
import { uomService, CreateUomDto, UpdateUomDto } from './uom.service.js';
import { productCategoriesService, CreateProductCategoryDto, UpdateProductCategoryDto } from './product-categories.service.js';
import { AuthenticatedRequest } from '../../shared/middleware/auth.middleware.js';
import { ValidationError } from '../../shared/errors/index.js';

// Schemas
const createCurrencySchema = z.object({
  code: z.string().length(3, 'El código debe tener 3 caracteres').toUpperCase(),
  name: z.string().min(1, 'El nombre es requerido').max(100),
  symbol: z.string().min(1).max(10),
  decimal_places: z.number().int().min(0).max(6).default(2),
});

const updateCurrencySchema = z.object({
  name: z.string().min(1).max(100).optional(),
  symbol: z.string().min(1).max(10).optional(),
  decimal_places: z.number().int().min(0).max(6).optional(),
  active: z.boolean().optional(),
});

const createUomSchema = z.object({
  name: z.string().min(1, 'El nombre es requerido').max(100),
  code: z.string().min(1).max(20),
  category_id: z.string().uuid(),
  uom_type: z.enum(['reference', 'bigger', 'smaller']).default('reference'),
  ratio: z.number().positive().default(1),
});

const updateUomSchema = z.object({
  name: z.string().min(1).max(100).optional(),
  ratio: z.number().positive().optional(),
  active: z.boolean().optional(),
});

const createCategorySchema = z.object({
  name: z.string().min(1, 'El nombre es requerido').max(100),
  code: z.string().min(1).max(50),
  parent_id: z.string().uuid().optional(),
});

const updateCategorySchema = z.object({
  name: z.string().min(1).max(100).optional(),
  parent_id: z.string().uuid().optional().nullable(),
  active: z.boolean().optional(),
});

class CoreController {
  // ========== CURRENCIES ==========
  async getCurrencies(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const activeOnly = req.query.active === 'true';
      const currencies = await currenciesService.findAll(activeOnly);
      res.json({ success: true, data: currencies });
    } catch (error) {
      next(error);
    }
  }

  async getCurrency(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const currency = await currenciesService.findById(req.params.id);
      res.json({ success: true, data: currency });
    } catch (error) {
      next(error);
    }
  }

  async createCurrency(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createCurrencySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de moneda inválidos', parseResult.error.errors);
      }
      const dto: CreateCurrencyDto = parseResult.data;
      const currency = await currenciesService.create(dto);
      res.status(201).json({ success: true, data: currency, message: 'Moneda creada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateCurrency(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateCurrencySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de moneda inválidos', parseResult.error.errors);
      }
      const dto: UpdateCurrencyDto = parseResult.data;
      const currency = await currenciesService.update(req.params.id, dto);
      res.json({ success: true, data: currency, message: 'Moneda actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== COUNTRIES ==========
  async getCountries(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const countries = await countriesService.findAll();
      res.json({ success: true, data: countries });
    } catch (error) {
      next(error);
    }
  }

  async getCountry(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const country = await countriesService.findById(req.params.id);
      res.json({ success: true, data: country });
    } catch (error) {
      next(error);
    }
  }

  // ========== UOM CATEGORIES ==========
  async getUomCategories(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const activeOnly = req.query.active === 'true';
      const categories = await uomService.findAllCategories(activeOnly);
      res.json({ success: true, data: categories });
    } catch (error) {
      next(error);
    }
  }

  async getUomCategory(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const category = await uomService.findCategoryById(req.params.id);
      res.json({ success: true, data: category });
    } catch (error) {
      next(error);
    }
  }

  // ========== UOM ==========
  async getUoms(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const activeOnly = req.query.active === 'true';
      const categoryId = req.query.category_id as string | undefined;
      const uoms = await uomService.findAll(categoryId, activeOnly);
      res.json({ success: true, data: uoms });
    } catch (error) {
      next(error);
    }
  }

  async getUom(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const uom = await uomService.findById(req.params.id);
      res.json({ success: true, data: uom });
    } catch (error) {
      next(error);
    }
  }

  async createUom(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createUomSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de UdM inválidos', parseResult.error.errors);
      }
      const dto: CreateUomDto = parseResult.data;
      const uom = await uomService.create(dto);
      res.status(201).json({ success: true, data: uom, message: 'Unidad de medida creada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateUom(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateUomSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de UdM inválidos', parseResult.error.errors);
      }
      const dto: UpdateUomDto = parseResult.data;
      const uom = await uomService.update(req.params.id, dto);
      res.json({ success: true, data: uom, message: 'Unidad de medida actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== PRODUCT CATEGORIES ==========
  async getProductCategories(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const activeOnly = req.query.active === 'true';
      const parentId = req.query.parent_id as string | undefined;
      const categories = await productCategoriesService.findAll(req.tenantId!, parentId, activeOnly);
      res.json({ success: true, data: categories });
    } catch (error) {
      next(error);
    }
  }

  async getProductCategory(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const category = await productCategoriesService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: category });
    } catch (error) {
      next(error);
    }
  }

  async createProductCategory(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createCategorySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de categoría inválidos', parseResult.error.errors);
      }
      const dto: CreateProductCategoryDto = parseResult.data;
      const category = await productCategoriesService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: category, message: 'Categoría creada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateProductCategory(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateCategorySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de categoría inválidos', parseResult.error.errors);
      }
      const dto: UpdateProductCategoryDto = parseResult.data;
      const category = await productCategoriesService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: category, message: 'Categoría actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async deleteProductCategory(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await productCategoriesService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Categoría eliminada exitosamente' });
    } catch (error) {
      next(error);
    }
  }
}

export const coreController = new CoreController();
