import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { partnersService, CreatePartnerDto, UpdatePartnerDto, PartnerFilters, PartnerType } from './partners.service.js';
import { ApiResponse, AuthenticatedRequest, ValidationError } from '../../shared/types/index.js';

// Validation schemas (accept both snake_case and camelCase from frontend)
const createPartnerSchema = z.object({
  code: z.string().min(1, 'El código es requerido').max(20),
  display_name: z.string().min(1).max(200).optional(),
  displayName: z.string().min(1, 'El nombre es requerido').max(200).optional(),
  legal_name: z.string().max(200).optional(),
  legalName: z.string().max(200).optional(),
  partner_type: z.enum(['customer', 'supplier', 'both']).default('customer'),
  partnerType: z.enum(['customer', 'supplier', 'both']).default('customer'),
  email: z.string().email('Email inválido').max(255).optional(),
  phone: z.string().max(30).optional(),
  mobile: z.string().max(30).optional(),
  website: z.string().max(500).optional(),
  tax_id: z.string().max(20).optional(),
  taxId: z.string().max(20).optional(),
  tax_regime: z.string().max(100).optional(),
  taxRegime: z.string().max(100).optional(),
  cfdi_use: z.string().max(10).optional(),
  cfdiUse: z.string().max(10).optional(),
  payment_term_days: z.coerce.number().int().default(0),
  paymentTermDays: z.coerce.number().int().default(0),
  credit_limit: z.coerce.number().default(0),
  creditLimit: z.coerce.number().default(0),
  price_list_id: z.string().uuid().optional(),
  priceListId: z.string().uuid().optional(),
  discount_percent: z.coerce.number().default(0),
  discountPercent: z.coerce.number().default(0),
  category: z.string().max(50).optional(),
  tags: z.array(z.string()).optional(),
  notes: z.string().optional(),
  sales_rep_id: z.string().uuid().optional(),
  salesRepId: z.string().uuid().optional(),
});

const updatePartnerSchema = z.object({
  display_name: z.string().min(1).max(200).optional(),
  displayName: z.string().min(1).max(200).optional(),
  legal_name: z.string().max(200).optional().nullable(),
  legalName: z.string().max(200).optional().nullable(),
  partner_type: z.enum(['customer', 'supplier', 'both']).optional(),
  partnerType: z.enum(['customer', 'supplier', 'both']).optional(),
  email: z.string().email('Email inválido').max(255).optional().nullable(),
  phone: z.string().max(30).optional().nullable(),
  mobile: z.string().max(30).optional().nullable(),
  website: z.string().max(500).optional().nullable(),
  tax_id: z.string().max(20).optional().nullable(),
  taxId: z.string().max(20).optional().nullable(),
  tax_regime: z.string().max(100).optional().nullable(),
  taxRegime: z.string().max(100).optional().nullable(),
  cfdi_use: z.string().max(10).optional().nullable(),
  cfdiUse: z.string().max(10).optional().nullable(),
  payment_term_days: z.coerce.number().int().optional(),
  paymentTermDays: z.coerce.number().int().optional(),
  credit_limit: z.coerce.number().optional(),
  creditLimit: z.coerce.number().optional(),
  price_list_id: z.string().uuid().optional().nullable(),
  priceListId: z.string().uuid().optional().nullable(),
  discount_percent: z.coerce.number().optional(),
  discountPercent: z.coerce.number().optional(),
  category: z.string().max(50).optional().nullable(),
  tags: z.array(z.string()).optional(),
  notes: z.string().optional().nullable(),
  is_active: z.boolean().optional(),
  isActive: z.boolean().optional(),
  is_verified: z.boolean().optional(),
  isVerified: z.boolean().optional(),
  sales_rep_id: z.string().uuid().optional().nullable(),
  salesRepId: z.string().uuid().optional().nullable(),
});

const querySchema = z.object({
  search: z.string().optional(),
  partner_type: z.enum(['customer', 'supplier', 'both']).optional(),
  partnerType: z.enum(['customer', 'supplier', 'both']).optional(),
  category: z.string().optional(),
  is_active: z.coerce.boolean().optional(),
  isActive: z.coerce.boolean().optional(),
  is_verified: z.coerce.boolean().optional(),
  isVerified: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

class PartnersController {
  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 data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters: PartnerFilters = {
        search: data.search,
        partnerType: (data.partnerType || data.partner_type) as PartnerType | undefined,
        category: data.category,
        isActive: data.isActive ?? data.is_active,
        isVerified: data.isVerified ?? data.is_verified,
        page: data.page,
        limit: data.limit,
      };

      const result = await partnersService.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 findCustomers(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 data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters = {
        search: data.search,
        category: data.category,
        isActive: data.isActive ?? data.is_active,
        isVerified: data.isVerified ?? data.is_verified,
        page: data.page,
        limit: data.limit,
      };

      const result = await partnersService.findCustomers(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 findSuppliers(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 data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters = {
        search: data.search,
        category: data.category,
        isActive: data.isActive ?? data.is_active,
        isVerified: data.isVerified ?? data.is_verified,
        page: data.page,
        limit: data.limit,
      };

      const result = await partnersService.findSuppliers(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 partner = await partnersService.findById(id, tenantId);

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

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

  async create(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createPartnerSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de contacto 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: CreatePartnerDto = {
        code: data.code,
        displayName: data.displayName || data.display_name || data.code,
        legalName: data.legalName || data.legal_name,
        partnerType: (data.partnerType || data.partner_type) as PartnerType,
        email: data.email,
        phone: data.phone,
        mobile: data.mobile,
        website: data.website,
        taxId: data.taxId || data.tax_id,
        taxRegime: data.taxRegime || data.tax_regime,
        cfdiUse: data.cfdiUse || data.cfdi_use,
        paymentTermDays: data.paymentTermDays || data.payment_term_days,
        creditLimit: data.creditLimit || data.credit_limit,
        priceListId: data.priceListId || data.price_list_id,
        discountPercent: data.discountPercent || data.discount_percent,
        category: data.category,
        tags: data.tags,
        notes: data.notes,
        salesRepId: data.salesRepId || data.sales_rep_id,
      };

      const partner = await partnersService.create(dto, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: partner,
        message: 'Contacto creado 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 = updatePartnerSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de contacto 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: UpdatePartnerDto = {};

      if (data.displayName !== undefined || data.display_name !== undefined) {
        dto.displayName = data.displayName ?? data.display_name;
      }
      if (data.legalName !== undefined || data.legal_name !== undefined) {
        dto.legalName = data.legalName ?? data.legal_name;
      }
      if (data.partnerType !== undefined || data.partner_type !== undefined) {
        dto.partnerType = (data.partnerType ?? data.partner_type) as PartnerType;
      }
      if (data.email !== undefined) dto.email = data.email;
      if (data.phone !== undefined) dto.phone = data.phone;
      if (data.mobile !== undefined) dto.mobile = data.mobile;
      if (data.website !== undefined) dto.website = data.website;
      if (data.taxId !== undefined || data.tax_id !== undefined) {
        dto.taxId = data.taxId ?? data.tax_id;
      }
      if (data.taxRegime !== undefined || data.tax_regime !== undefined) {
        dto.taxRegime = data.taxRegime ?? data.tax_regime;
      }
      if (data.cfdiUse !== undefined || data.cfdi_use !== undefined) {
        dto.cfdiUse = data.cfdiUse ?? data.cfdi_use;
      }
      if (data.paymentTermDays !== undefined || data.payment_term_days !== undefined) {
        dto.paymentTermDays = data.paymentTermDays ?? data.payment_term_days;
      }
      if (data.creditLimit !== undefined || data.credit_limit !== undefined) {
        dto.creditLimit = data.creditLimit ?? data.credit_limit;
      }
      if (data.priceListId !== undefined || data.price_list_id !== undefined) {
        dto.priceListId = data.priceListId ?? data.price_list_id;
      }
      if (data.discountPercent !== undefined || data.discount_percent !== undefined) {
        dto.discountPercent = data.discountPercent ?? data.discount_percent;
      }
      if (data.category !== undefined) dto.category = data.category;
      if (data.tags !== undefined) dto.tags = data.tags;
      if (data.notes !== undefined) dto.notes = data.notes;
      if (data.isActive !== undefined || data.is_active !== undefined) {
        dto.isActive = data.isActive ?? data.is_active;
      }
      if (data.isVerified !== undefined || data.is_verified !== undefined) {
        dto.isVerified = data.isVerified ?? data.is_verified;
      }
      if (data.salesRepId !== undefined || data.sales_rep_id !== undefined) {
        dto.salesRepId = data.salesRepId ?? data.sales_rep_id;
      }

      const partner = await partnersService.update(id, dto, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: partner,
        message: 'Contacto actualizado 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 partnersService.delete(id, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        message: 'Contacto eliminado exitosamente',
      };

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

export const partnersController = new PartnersController();
