import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { companiesService, CreateCompanyDto, UpdateCompanyDto, CompanyFilters } from './companies.service.js';
import { ApiResponse, AuthenticatedRequest, ValidationError } from '../../shared/types/index.js';

// Validation schemas (accept both snake_case and camelCase from frontend)
const createCompanySchema = z.object({
  name: z.string().min(1, 'El nombre es requerido').max(255),
  legal_name: z.string().max(255).optional(),
  legalName: z.string().max(255).optional(),
  tax_id: z.string().max(50).optional(),
  taxId: z.string().max(50).optional(),
  currency_id: z.string().uuid().optional(),
  currencyId: z.string().uuid().optional(),
  parent_company_id: z.string().uuid().optional(),
  parentCompanyId: z.string().uuid().optional(),
  settings: z.record(z.any()).optional(),
});

const updateCompanySchema = z.object({
  name: z.string().min(1).max(255).optional(),
  legal_name: z.string().max(255).optional().nullable(),
  legalName: z.string().max(255).optional().nullable(),
  tax_id: z.string().max(50).optional().nullable(),
  taxId: z.string().max(50).optional().nullable(),
  currency_id: z.string().uuid().optional().nullable(),
  currencyId: z.string().uuid().optional().nullable(),
  parent_company_id: z.string().uuid().optional().nullable(),
  parentCompanyId: z.string().uuid().optional().nullable(),
  settings: z.record(z.any()).optional(),
});

const querySchema = z.object({
  search: z.string().optional(),
  parent_company_id: z.string().uuid().optional(),
  parentCompanyId: z.string().uuid().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

class CompaniesController {
  async findAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = querySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const tenantId = req.user!.tenantId;
      const filters: CompanyFilters = {
        search: queryResult.data.search,
        parentCompanyId: queryResult.data.parentCompanyId || queryResult.data.parent_company_id,
        page: queryResult.data.page,
        limit: queryResult.data.limit,
      };

      const result = await companiesService.findAll(tenantId, filters);

      const response: ApiResponse = {
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page || 1,
          limit: filters.limit || 20,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async findById(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const company = await companiesService.findById(id, tenantId);

      const response: ApiResponse = {
        success: true,
        data: company,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async create(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createCompanySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de empresa inválidos', parseResult.error.errors);
      }

      const data = parseResult.data;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      // Transform to camelCase DTO
      const dto: CreateCompanyDto = {
        name: data.name,
        legalName: data.legalName || data.legal_name,
        taxId: data.taxId || data.tax_id,
        currencyId: data.currencyId || data.currency_id,
        parentCompanyId: data.parentCompanyId || data.parent_company_id,
        settings: data.settings,
      };

      const company = await companiesService.create(dto, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: company,
        message: 'Empresa creada exitosamente',
      };

      res.status(201).json(response);
    } catch (error) {
      next(error);
    }
  }

  async update(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const parseResult = updateCompanySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de empresa inválidos', parseResult.error.errors);
      }

      const data = parseResult.data;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      // Transform to camelCase DTO
      const dto: UpdateCompanyDto = {};
      if (data.name !== undefined) dto.name = data.name;
      if (data.legalName !== undefined || data.legal_name !== undefined) {
        dto.legalName = data.legalName ?? data.legal_name;
      }
      if (data.taxId !== undefined || data.tax_id !== undefined) {
        dto.taxId = data.taxId ?? data.tax_id;
      }
      if (data.currencyId !== undefined || data.currency_id !== undefined) {
        dto.currencyId = data.currencyId ?? data.currency_id;
      }
      if (data.parentCompanyId !== undefined || data.parent_company_id !== undefined) {
        dto.parentCompanyId = data.parentCompanyId ?? data.parent_company_id;
      }
      if (data.settings !== undefined) dto.settings = data.settings;

      const company = await companiesService.update(id, dto, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: company,
        message: 'Empresa actualizada exitosamente',
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async delete(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      await companiesService.delete(id, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        message: 'Empresa eliminada exitosamente',
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async getUsers(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const users = await companiesService.getUsers(id, tenantId);

      const response: ApiResponse = {
        success: true,
        data: users,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async getSubsidiaries(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const subsidiaries = await companiesService.getSubsidiaries(id, tenantId);

      const response: ApiResponse = {
        success: true,
        data: subsidiaries,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async getHierarchy(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const hierarchy = await companiesService.getHierarchy(tenantId);

      const response: ApiResponse = {
        success: true,
        data: hierarchy,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }
}

export const companiesController = new CompaniesController();
