import { Response, NextFunction } from 'express';
import { z } from 'zod';
import {
  cfdiService,
  CreateCfdiInvoiceDto,
  UpdateCfdiInvoiceDto,
  CfdiFilters,
  CertificateFilters,
  UploadCertificateDto,
  CancellationRequestDto,
} from './services/index.js';
import { CfdiStatus } from './enums/cfdi-status.enum.js';
import { CancellationReason } from './enums/cancellation-reason.enum.js';
import { CfdiVoucherType } from './entities/cfdi-invoice.entity.js';
import { CertificateStatus } from './entities/cfdi-certificate.entity.js';
import { ApiResponse, AuthenticatedRequest, ValidationError } from '../../shared/types/index.js';

// ===== Zod Validation Schemas =====

const cfdiStatusValues = ['draft', 'pending', 'processing', 'stamped', 'error', 'cancelled', 'cancellation_pending', 'cancellation_rejected'] as const;
const voucherTypeValues = ['I', 'E', 'T', 'N', 'P'] as const;
const cancellationReasonValues = ['01', '02', '03', '04'] as const;
const certificateStatusValues = ['active', 'inactive', 'expired', 'revoked', 'pending'] as const;

const createCfdiSchema = z.object({
  // Dual case support (snake_case from frontend, camelCase)
  invoice_id: z.string().uuid().optional(),
  invoiceId: z.string().uuid().optional(),
  certificate_id: z.string().uuid().optional(),
  certificateId: z.string().uuid().optional(),
  serie: z.string().max(25).optional(),
  folio: z.string().max(40).optional(),
  cfdi_version: z.string().max(5).optional(),
  cfdiVersion: z.string().max(5).optional(),
  voucher_type: z.enum(voucherTypeValues).optional(),
  voucherType: z.enum(voucherTypeValues).optional(),
  // Issuer (Emisor)
  issuer_rfc: z.string().min(12).max(13).optional(),
  issuerRfc: z.string().min(12).max(13).optional(),
  issuer_name: z.string().min(1).max(300).optional(),
  issuerName: z.string().min(1).max(300).optional(),
  issuer_fiscal_regime: z.string().max(10).optional(),
  issuerFiscalRegime: z.string().max(10).optional(),
  // Receiver (Receptor)
  receiver_rfc: z.string().min(12).max(13).optional(),
  receiverRfc: z.string().min(12).max(13).optional(),
  receiver_name: z.string().min(1).max(300).optional(),
  receiverName: z.string().min(1).max(300).optional(),
  receiver_fiscal_regime: z.string().max(10).optional(),
  receiverFiscalRegime: z.string().max(10).optional(),
  receiver_zip_code: z.string().max(5).optional(),
  receiverZipCode: z.string().max(5).optional(),
  receiver_tax_residence: z.string().max(3).optional(),
  receiverTaxResidence: z.string().max(3).optional(),
  receiver_tax_id: z.string().max(40).optional(),
  receiverTaxId: z.string().max(40).optional(),
  cfdi_use: z.string().max(10).optional(),
  cfdiUse: z.string().max(10).optional(),
  // Amounts
  subtotal: z.coerce.number().min(0),
  discount: z.coerce.number().min(0).optional(),
  total: z.coerce.number().min(0),
  total_transferred_taxes: z.coerce.number().optional(),
  totalTransferredTaxes: z.coerce.number().optional(),
  total_withheld_taxes: z.coerce.number().optional(),
  totalWithheldTaxes: z.coerce.number().optional(),
  currency: z.string().max(3).optional(),
  exchange_rate: z.coerce.number().optional(),
  exchangeRate: z.coerce.number().optional(),
  exportation: z.string().max(2).optional(),
  // Payment
  payment_form: z.string().max(10).optional(),
  paymentForm: z.string().max(10).optional(),
  payment_method: z.string().max(10).optional(),
  paymentMethod: z.string().max(10).optional(),
  payment_conditions: z.string().max(1000).optional(),
  paymentConditions: z.string().max(1000).optional(),
  // Location
  expedition_place: z.string().max(5).optional(),
  expeditionPlace: z.string().max(5).optional(),
  confirmation_code: z.string().max(17).optional(),
  confirmationCode: z.string().max(17).optional(),
  // Related CFDI
  related_cfdi_type: z.string().max(10).optional(),
  relatedCfdiType: z.string().max(10).optional(),
  // Global info
  global_info_periodicity: z.string().max(10).optional(),
  globalInfoPeriodicity: z.string().max(10).optional(),
  global_info_months: z.string().max(10).optional(),
  globalInfoMonths: z.string().max(10).optional(),
  global_info_year: z.string().max(4).optional(),
  globalInfoYear: z.string().max(4).optional(),
});

const updateCfdiSchema = z.object({
  invoice_id: z.string().uuid().optional().nullable(),
  invoiceId: z.string().uuid().optional().nullable(),
  certificate_id: z.string().uuid().optional().nullable(),
  certificateId: z.string().uuid().optional().nullable(),
  serie: z.string().max(25).optional().nullable(),
  folio: z.string().max(40).optional().nullable(),
  voucher_type: z.enum(voucherTypeValues).optional(),
  voucherType: z.enum(voucherTypeValues).optional(),
  issuer_rfc: z.string().min(12).max(13).optional(),
  issuerRfc: z.string().min(12).max(13).optional(),
  issuer_name: z.string().min(1).max(300).optional(),
  issuerName: z.string().min(1).max(300).optional(),
  issuer_fiscal_regime: z.string().max(10).optional(),
  issuerFiscalRegime: z.string().max(10).optional(),
  receiver_rfc: z.string().min(12).max(13).optional(),
  receiverRfc: z.string().min(12).max(13).optional(),
  receiver_name: z.string().min(1).max(300).optional(),
  receiverName: z.string().min(1).max(300).optional(),
  receiver_fiscal_regime: z.string().max(10).optional().nullable(),
  receiverFiscalRegime: z.string().max(10).optional().nullable(),
  receiver_zip_code: z.string().max(5).optional().nullable(),
  receiverZipCode: z.string().max(5).optional().nullable(),
  receiver_tax_residence: z.string().max(3).optional().nullable(),
  receiverTaxResidence: z.string().max(3).optional().nullable(),
  receiver_tax_id: z.string().max(40).optional().nullable(),
  receiverTaxId: z.string().max(40).optional().nullable(),
  cfdi_use: z.string().max(10).optional(),
  cfdiUse: z.string().max(10).optional(),
  subtotal: z.coerce.number().min(0).optional(),
  discount: z.coerce.number().min(0).optional().nullable(),
  total: z.coerce.number().min(0).optional(),
  total_transferred_taxes: z.coerce.number().optional().nullable(),
  totalTransferredTaxes: z.coerce.number().optional().nullable(),
  total_withheld_taxes: z.coerce.number().optional().nullable(),
  totalWithheldTaxes: z.coerce.number().optional().nullable(),
  currency: z.string().max(3).optional(),
  exchange_rate: z.coerce.number().optional().nullable(),
  exchangeRate: z.coerce.number().optional().nullable(),
  exportation: z.string().max(2).optional().nullable(),
  payment_form: z.string().max(10).optional(),
  paymentForm: z.string().max(10).optional(),
  payment_method: z.string().max(10).optional(),
  paymentMethod: z.string().max(10).optional(),
  payment_conditions: z.string().max(1000).optional().nullable(),
  paymentConditions: z.string().max(1000).optional().nullable(),
  expedition_place: z.string().max(5).optional(),
  expeditionPlace: z.string().max(5).optional(),
  confirmation_code: z.string().max(17).optional().nullable(),
  confirmationCode: z.string().max(17).optional().nullable(),
  related_cfdi_type: z.string().max(10).optional().nullable(),
  relatedCfdiType: z.string().max(10).optional().nullable(),
  global_info_periodicity: z.string().max(10).optional().nullable(),
  globalInfoPeriodicity: z.string().max(10).optional().nullable(),
  global_info_months: z.string().max(10).optional().nullable(),
  globalInfoMonths: z.string().max(10).optional().nullable(),
  global_info_year: z.string().max(4).optional().nullable(),
  globalInfoYear: z.string().max(4).optional().nullable(),
});

const cfdiQuerySchema = z.object({
  search: z.string().optional(),
  status: z.enum(cfdiStatusValues).optional(),
  voucher_type: z.enum(voucherTypeValues).optional(),
  voucherType: z.enum(voucherTypeValues).optional(),
  issuer_rfc: z.string().optional(),
  issuerRfc: z.string().optional(),
  receiver_rfc: z.string().optional(),
  receiverRfc: z.string().optional(),
  serie: z.string().optional(),
  folio: z.string().optional(),
  date_from: z.string().optional(),
  dateFrom: z.string().optional(),
  date_to: z.string().optional(),
  dateTo: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

const cancelCfdiSchema = z.object({
  cancellation_reason: z.enum(cancellationReasonValues).optional(),
  cancellationReason: z.enum(cancellationReasonValues).optional(),
  substitute_uuid: z.string().uuid().optional(),
  substituteUuid: z.string().uuid().optional(),
  substitute_cfdi_id: z.string().uuid().optional(),
  substituteCfdiId: z.string().uuid().optional(),
  reason_notes: z.string().max(2000).optional(),
  reasonNotes: z.string().max(2000).optional(),
  internal_notes: z.string().max(2000).optional(),
  internalNotes: z.string().max(2000).optional(),
});

const certificateQuerySchema = z.object({
  rfc: z.string().optional(),
  status: z.enum(certificateStatusValues).optional(),
  is_default: z.coerce.boolean().optional(),
  isDefault: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

const uploadCertificateSchema = z.object({
  rfc: z.string().min(12).max(13),
  certificate_number: z.string().max(20).optional(),
  certificateNumber: z.string().max(20).optional(),
  certificate_pem: z.string().min(1).optional(),
  certificatePem: z.string().min(1).optional(),
  private_key_pem_encrypted: z.string().min(1).optional(),
  privateKeyPemEncrypted: z.string().min(1).optional(),
  serial_number: z.string().max(100).optional(),
  serialNumber: z.string().max(100).optional(),
  issued_at: z.string().optional(),
  issuedAt: z.string().optional(),
  expires_at: z.string().optional(),
  expiresAt: z.string().optional(),
  is_default: z.boolean().optional(),
  isDefault: z.boolean().optional(),
  issuer_name: z.string().max(500).optional(),
  issuerName: z.string().max(500).optional(),
  subject_name: z.string().max(500).optional(),
  subjectName: z.string().max(500).optional(),
  description: z.string().max(255).optional(),
  notes: z.string().optional(),
});

// ===== CfdiController Class =====

class CfdiController {
  /**
   * GET /api/cfdi - List CFDI invoices with filters and pagination
   */
  async findAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = cfdiQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parametros de consulta invalidos', queryResult.error.errors);
      }

      const data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters: CfdiFilters = {
        search: data.search,
        status: data.status as CfdiStatus | undefined,
        voucherType: data.voucherType || data.voucher_type,
        issuerRfc: data.issuerRfc || data.issuer_rfc,
        receiverRfc: data.receiverRfc || data.receiver_rfc,
        serie: data.serie,
        folio: data.folio,
        dateFrom: data.dateFrom || data.date_from,
        dateTo: data.dateTo || data.date_to,
        page: data.page,
        limit: data.limit,
      };

      const result = await cfdiService.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);
    }
  }

  /**
   * GET /api/cfdi/:id - Get single CFDI by ID
   */
  async findById(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const invoice = await cfdiService.findById(tenantId, id);

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

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

  /**
   * POST /api/cfdi - Create new CFDI invoice in draft
   */
  async create(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createCfdiSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de CFDI invalidos', parseResult.error.errors);
      }

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

      // Transform to camelCase DTO
      const dto: CreateCfdiInvoiceDto = {
        issuerRfc: (data.issuerRfc || data.issuer_rfc)!,
        issuerName: (data.issuerName || data.issuer_name)!,
        issuerFiscalRegime: (data.issuerFiscalRegime || data.issuer_fiscal_regime)!,
        receiverRfc: (data.receiverRfc || data.receiver_rfc)!,
        receiverName: (data.receiverName || data.receiver_name)!,
        cfdiUse: (data.cfdiUse || data.cfdi_use)!,
        subtotal: data.subtotal,
        total: data.total,
        paymentForm: (data.paymentForm || data.payment_form)!,
        paymentMethod: (data.paymentMethod || data.payment_method)!,
        expeditionPlace: (data.expeditionPlace || data.expedition_place)!,
      };

      // Optional fields
      if (data.invoiceId !== undefined || data.invoice_id !== undefined) {
        dto.invoiceId = data.invoiceId || data.invoice_id;
      }
      if (data.certificateId !== undefined || data.certificate_id !== undefined) {
        dto.certificateId = data.certificateId || data.certificate_id;
      }
      if (data.serie !== undefined) dto.serie = data.serie;
      if (data.folio !== undefined) dto.folio = data.folio;
      if (data.cfdiVersion !== undefined || data.cfdi_version !== undefined) {
        dto.cfdiVersion = data.cfdiVersion || data.cfdi_version;
      }
      if (data.voucherType !== undefined || data.voucher_type !== undefined) {
        dto.voucherType = data.voucherType || data.voucher_type;
      }
      if (data.receiverFiscalRegime !== undefined || data.receiver_fiscal_regime !== undefined) {
        dto.receiverFiscalRegime = data.receiverFiscalRegime || data.receiver_fiscal_regime;
      }
      if (data.receiverZipCode !== undefined || data.receiver_zip_code !== undefined) {
        dto.receiverZipCode = data.receiverZipCode || data.receiver_zip_code;
      }
      if (data.receiverTaxResidence !== undefined || data.receiver_tax_residence !== undefined) {
        dto.receiverTaxResidence = data.receiverTaxResidence || data.receiver_tax_residence;
      }
      if (data.receiverTaxId !== undefined || data.receiver_tax_id !== undefined) {
        dto.receiverTaxId = data.receiverTaxId || data.receiver_tax_id;
      }
      if (data.discount !== undefined) dto.discount = data.discount;
      if (data.totalTransferredTaxes !== undefined || data.total_transferred_taxes !== undefined) {
        dto.totalTransferredTaxes = data.totalTransferredTaxes ?? data.total_transferred_taxes;
      }
      if (data.totalWithheldTaxes !== undefined || data.total_withheld_taxes !== undefined) {
        dto.totalWithheldTaxes = data.totalWithheldTaxes ?? data.total_withheld_taxes;
      }
      if (data.currency !== undefined) dto.currency = data.currency;
      if (data.exchangeRate !== undefined || data.exchange_rate !== undefined) {
        dto.exchangeRate = data.exchangeRate ?? data.exchange_rate;
      }
      if (data.exportation !== undefined) dto.exportation = data.exportation;
      if (data.paymentConditions !== undefined || data.payment_conditions !== undefined) {
        dto.paymentConditions = data.paymentConditions || data.payment_conditions;
      }
      if (data.confirmationCode !== undefined || data.confirmation_code !== undefined) {
        dto.confirmationCode = data.confirmationCode || data.confirmation_code;
      }
      if (data.relatedCfdiType !== undefined || data.related_cfdi_type !== undefined) {
        dto.relatedCfdiType = data.relatedCfdiType || data.related_cfdi_type;
      }
      if (data.globalInfoPeriodicity !== undefined || data.global_info_periodicity !== undefined) {
        dto.globalInfoPeriodicity = data.globalInfoPeriodicity || data.global_info_periodicity;
      }
      if (data.globalInfoMonths !== undefined || data.global_info_months !== undefined) {
        dto.globalInfoMonths = data.globalInfoMonths || data.global_info_months;
      }
      if (data.globalInfoYear !== undefined || data.global_info_year !== undefined) {
        dto.globalInfoYear = data.globalInfoYear || data.global_info_year;
      }

      const invoice = await cfdiService.create(tenantId, dto, userId);

      const response: ApiResponse = {
        success: true,
        data: invoice,
        message: 'CFDI creado exitosamente en estado borrador',
      };

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

  /**
   * PUT /api/cfdi/:id - Update a draft CFDI
   */
  async update(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const parseResult = updateCfdiSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de CFDI invalidos', parseResult.error.errors);
      }

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

      // Transform to camelCase DTO
      const dto: UpdateCfdiInvoiceDto = {};

      if (data.invoiceId !== undefined || data.invoice_id !== undefined) {
        dto.invoiceId = data.invoiceId ?? data.invoice_id;
      }
      if (data.certificateId !== undefined || data.certificate_id !== undefined) {
        dto.certificateId = data.certificateId ?? data.certificate_id;
      }
      if (data.serie !== undefined) dto.serie = data.serie;
      if (data.folio !== undefined) dto.folio = data.folio;
      if (data.voucherType !== undefined || data.voucher_type !== undefined) {
        dto.voucherType = data.voucherType ?? data.voucher_type;
      }
      if (data.issuerRfc !== undefined || data.issuer_rfc !== undefined) {
        dto.issuerRfc = data.issuerRfc ?? data.issuer_rfc;
      }
      if (data.issuerName !== undefined || data.issuer_name !== undefined) {
        dto.issuerName = data.issuerName ?? data.issuer_name;
      }
      if (data.issuerFiscalRegime !== undefined || data.issuer_fiscal_regime !== undefined) {
        dto.issuerFiscalRegime = data.issuerFiscalRegime ?? data.issuer_fiscal_regime;
      }
      if (data.receiverRfc !== undefined || data.receiver_rfc !== undefined) {
        dto.receiverRfc = data.receiverRfc ?? data.receiver_rfc;
      }
      if (data.receiverName !== undefined || data.receiver_name !== undefined) {
        dto.receiverName = data.receiverName ?? data.receiver_name;
      }
      if (data.receiverFiscalRegime !== undefined || data.receiver_fiscal_regime !== undefined) {
        dto.receiverFiscalRegime = data.receiverFiscalRegime ?? data.receiver_fiscal_regime;
      }
      if (data.receiverZipCode !== undefined || data.receiver_zip_code !== undefined) {
        dto.receiverZipCode = data.receiverZipCode ?? data.receiver_zip_code;
      }
      if (data.receiverTaxResidence !== undefined || data.receiver_tax_residence !== undefined) {
        dto.receiverTaxResidence = data.receiverTaxResidence ?? data.receiver_tax_residence;
      }
      if (data.receiverTaxId !== undefined || data.receiver_tax_id !== undefined) {
        dto.receiverTaxId = data.receiverTaxId ?? data.receiver_tax_id;
      }
      if (data.cfdiUse !== undefined || data.cfdi_use !== undefined) {
        dto.cfdiUse = data.cfdiUse ?? data.cfdi_use;
      }
      if (data.subtotal !== undefined) dto.subtotal = data.subtotal;
      if (data.discount !== undefined) dto.discount = data.discount;
      if (data.total !== undefined) dto.total = data.total;
      if (data.totalTransferredTaxes !== undefined || data.total_transferred_taxes !== undefined) {
        dto.totalTransferredTaxes = data.totalTransferredTaxes ?? data.total_transferred_taxes;
      }
      if (data.totalWithheldTaxes !== undefined || data.total_withheld_taxes !== undefined) {
        dto.totalWithheldTaxes = data.totalWithheldTaxes ?? data.total_withheld_taxes;
      }
      if (data.currency !== undefined) dto.currency = data.currency;
      if (data.exchangeRate !== undefined || data.exchange_rate !== undefined) {
        dto.exchangeRate = data.exchangeRate ?? data.exchange_rate;
      }
      if (data.exportation !== undefined) dto.exportation = data.exportation;
      if (data.paymentForm !== undefined || data.payment_form !== undefined) {
        dto.paymentForm = data.paymentForm ?? data.payment_form;
      }
      if (data.paymentMethod !== undefined || data.payment_method !== undefined) {
        dto.paymentMethod = data.paymentMethod ?? data.payment_method;
      }
      if (data.paymentConditions !== undefined || data.payment_conditions !== undefined) {
        dto.paymentConditions = data.paymentConditions ?? data.payment_conditions;
      }
      if (data.expeditionPlace !== undefined || data.expedition_place !== undefined) {
        dto.expeditionPlace = data.expeditionPlace ?? data.expedition_place;
      }
      if (data.confirmationCode !== undefined || data.confirmation_code !== undefined) {
        dto.confirmationCode = data.confirmationCode ?? data.confirmation_code;
      }
      if (data.relatedCfdiType !== undefined || data.related_cfdi_type !== undefined) {
        dto.relatedCfdiType = data.relatedCfdiType ?? data.related_cfdi_type;
      }
      if (data.globalInfoPeriodicity !== undefined || data.global_info_periodicity !== undefined) {
        dto.globalInfoPeriodicity = data.globalInfoPeriodicity ?? data.global_info_periodicity;
      }
      if (data.globalInfoMonths !== undefined || data.global_info_months !== undefined) {
        dto.globalInfoMonths = data.globalInfoMonths ?? data.global_info_months;
      }
      if (data.globalInfoYear !== undefined || data.global_info_year !== undefined) {
        dto.globalInfoYear = data.globalInfoYear ?? data.global_info_year;
      }

      const invoice = await cfdiService.update(tenantId, id, dto, userId);

      const response: ApiResponse = {
        success: true,
        data: invoice,
        message: 'CFDI actualizado exitosamente',
      };

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

  /**
   * POST /api/cfdi/:id/stamp - Request stamping for a CFDI
   */
  async requestStamp(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      const invoice = await cfdiService.requestStamp(tenantId, id, userId);

      const response: ApiResponse = {
        success: true,
        data: invoice,
        message: 'Solicitud de timbrado registrada. El CFDI sera procesado en la cola de timbrado.',
      };

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

  /**
   * POST /api/cfdi/:id/cancel - Request cancellation for a CFDI
   */
  async requestCancellation(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const parseResult = cancelCfdiSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de cancelacion invalidos', parseResult.error.errors);
      }

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

      const reasonValue = data.cancellationReason || data.cancellation_reason;
      if (!reasonValue) {
        throw new ValidationError('El motivo de cancelacion es requerido (cancellationReason).');
      }

      const dto: CancellationRequestDto = {
        cancellationReason: reasonValue as CancellationReason,
        substituteUuid: data.substituteUuid || data.substitute_uuid,
        substituteCfdiId: data.substituteCfdiId || data.substitute_cfdi_id,
        reasonNotes: data.reasonNotes || data.reason_notes,
        internalNotes: data.internalNotes || data.internal_notes,
      };

      const cancellation = await cfdiService.requestCancellation(tenantId, id, dto, userId);

      const response: ApiResponse = {
        success: true,
        data: cancellation,
        message: 'Solicitud de cancelacion registrada exitosamente.',
      };

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

  /**
   * GET /api/cfdi/:id/status - Get CFDI status including SAT validation
   */
  async getStatus(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;

      const status = await cfdiService.getStatus(tenantId, id);

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

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

  /**
   * GET /api/cfdi/certificates - List certificates
   */
  async listCertificates(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = certificateQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parametros de consulta invalidos', queryResult.error.errors);
      }

      const data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters: CertificateFilters = {
        rfc: data.rfc,
        status: data.status as CertificateStatus | undefined,
        isDefault: data.isDefault ?? data.is_default,
        page: data.page,
        limit: data.limit,
      };

      const result = await cfdiService.listCertificates(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);
    }
  }

  /**
   * POST /api/cfdi/certificates - Upload a new certificate
   */
  async uploadCertificate(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = uploadCertificateSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de certificado invalidos', parseResult.error.errors);
      }

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

      const certificateNumber = data.certificateNumber || data.certificate_number;
      const certificatePem = data.certificatePem || data.certificate_pem;
      const privateKeyPemEncrypted = data.privateKeyPemEncrypted || data.private_key_pem_encrypted;
      const serialNumber = data.serialNumber || data.serial_number;
      const issuedAt = data.issuedAt || data.issued_at;
      const expiresAt = data.expiresAt || data.expires_at;

      if (!certificateNumber || !certificatePem || !privateKeyPemEncrypted || !serialNumber || !issuedAt || !expiresAt) {
        throw new ValidationError(
          'Campos requeridos faltantes: certificateNumber, certificatePem, privateKeyPemEncrypted, serialNumber, issuedAt, expiresAt'
        );
      }

      const dto: UploadCertificateDto = {
        rfc: data.rfc,
        certificateNumber,
        certificatePem,
        privateKeyPemEncrypted,
        serialNumber,
        issuedAt,
        expiresAt,
        isDefault: data.isDefault ?? data.is_default,
        issuerName: data.issuerName || data.issuer_name,
        subjectName: data.subjectName || data.subject_name,
        description: data.description,
        notes: data.notes,
      };

      const certificate = await cfdiService.uploadCertificate(tenantId, dto, userId);

      const response: ApiResponse = {
        success: true,
        data: certificate,
        message: 'Certificado registrado exitosamente',
      };

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

export const cfdiController = new CfdiController();
