import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { accountsService, CreateAccountDto, UpdateAccountDto, AccountFilters } from './accounts.service.js';
import { journalsService, CreateJournalDto, UpdateJournalDto, JournalFilters } from './journals.service.js';
import { journalEntriesService, CreateJournalEntryDto, UpdateJournalEntryDto, JournalEntryFilters } from './journal-entries.service.js';
import { invoicesService, CreateInvoiceDto, UpdateInvoiceDto, CreateInvoiceLineDto, UpdateInvoiceLineDto, InvoiceFilters } from './invoices.service.js';
import { paymentsService, CreatePaymentDto, UpdatePaymentDto, ReconcileDto, PaymentFilters } from './payments.service.js';
import { taxesService, CreateTaxDto, UpdateTaxDto, TaxFilters } from './taxes.service.js';
import { AuthenticatedRequest } from '../../shared/middleware/auth.middleware.js';
import { ValidationError } from '../../shared/errors/index.js';

// Schemas
const createAccountSchema = z.object({
  company_id: z.string().uuid(),
  code: z.string().min(1).max(50),
  name: z.string().min(1).max(255),
  account_type_id: z.string().uuid(),
  parent_id: z.string().uuid().optional(),
  currency_id: z.string().uuid().optional(),
  is_reconcilable: z.boolean().default(false),
  notes: z.string().optional(),
});

const updateAccountSchema = z.object({
  name: z.string().min(1).max(255).optional(),
  parent_id: z.string().uuid().optional().nullable(),
  currency_id: z.string().uuid().optional().nullable(),
  is_reconcilable: z.boolean().optional(),
  is_deprecated: z.boolean().optional(),
  notes: z.string().optional().nullable(),
});

const accountQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  account_type_id: z.string().uuid().optional(),
  parent_id: z.string().optional(),
  is_deprecated: z.coerce.boolean().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(50),
});

const createJournalSchema = z.object({
  company_id: z.string().uuid(),
  name: z.string().min(1).max(255),
  code: z.string().min(1).max(20),
  journal_type: z.enum(['sale', 'purchase', 'cash', 'bank', 'general']),
  default_account_id: z.string().uuid().optional(),
  sequence_id: z.string().uuid().optional(),
  currency_id: z.string().uuid().optional(),
});

const updateJournalSchema = z.object({
  name: z.string().min(1).max(255).optional(),
  default_account_id: z.string().uuid().optional().nullable(),
  sequence_id: z.string().uuid().optional().nullable(),
  currency_id: z.string().uuid().optional().nullable(),
  active: z.boolean().optional(),
});

const journalQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  journal_type: z.enum(['sale', 'purchase', 'cash', 'bank', 'general']).optional(),
  active: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(50),
});

const journalEntryLineSchema = z.object({
  account_id: z.string().uuid(),
  partner_id: z.string().uuid().optional(),
  debit: z.number().min(0).default(0),
  credit: z.number().min(0).default(0),
  description: z.string().optional(),
  ref: z.string().optional(),
});

const createJournalEntrySchema = z.object({
  company_id: z.string().uuid(),
  journal_id: z.string().uuid(),
  name: z.string().min(1).max(100),
  ref: z.string().max(255).optional(),
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
  notes: z.string().optional(),
  lines: z.array(journalEntryLineSchema).min(2),
});

const updateJournalEntrySchema = z.object({
  ref: z.string().max(255).optional().nullable(),
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  notes: z.string().optional().nullable(),
  lines: z.array(journalEntryLineSchema).min(2).optional(),
});

const journalEntryQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  journal_id: z.string().uuid().optional(),
  status: z.enum(['draft', 'posted', 'cancelled']).optional(),
  date_from: z.string().optional(),
  date_to: z.string().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

// ========== INVOICE SCHEMAS ==========
const createInvoiceSchema = z.object({
  company_id: z.string().uuid(),
  partner_id: z.string().uuid(),
  invoice_type: z.enum(['customer', 'supplier']),
  currency_id: z.string().uuid(),
  invoice_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  due_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  payment_term_id: z.string().uuid().optional(),
  journal_id: z.string().uuid().optional(),
  ref: z.string().optional(),
  notes: z.string().optional(),
});

const updateInvoiceSchema = z.object({
  partner_id: z.string().uuid().optional(),
  currency_id: z.string().uuid().optional(),
  invoice_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  due_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().nullable(),
  payment_term_id: z.string().uuid().optional().nullable(),
  journal_id: z.string().uuid().optional().nullable(),
  ref: z.string().optional().nullable(),
  notes: z.string().optional().nullable(),
});

const invoiceQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  partner_id: z.string().uuid().optional(),
  invoice_type: z.enum(['customer', 'supplier']).optional(),
  status: z.enum(['draft', 'open', 'paid', 'cancelled']).optional(),
  date_from: z.string().optional(),
  date_to: z.string().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

const createInvoiceLineSchema = z.object({
  product_id: z.string().uuid().optional(),
  description: z.string().min(1),
  quantity: z.number().positive(),
  uom_id: z.string().uuid().optional(),
  price_unit: z.number().min(0),
  tax_ids: z.array(z.string().uuid()).optional(),
  account_id: z.string().uuid().optional(),
});

const updateInvoiceLineSchema = z.object({
  product_id: z.string().uuid().optional().nullable(),
  description: z.string().min(1).optional(),
  quantity: z.number().positive().optional(),
  uom_id: z.string().uuid().optional().nullable(),
  price_unit: z.number().min(0).optional(),
  tax_ids: z.array(z.string().uuid()).optional(),
  account_id: z.string().uuid().optional().nullable(),
});

// ========== PAYMENT SCHEMAS ==========
const createPaymentSchema = z.object({
  company_id: z.string().uuid(),
  partner_id: z.string().uuid(),
  payment_type: z.enum(['inbound', 'outbound']),
  payment_method: z.enum(['cash', 'bank_transfer', 'check', 'card', 'other']),
  amount: z.number().positive(),
  currency_id: z.string().uuid(),
  payment_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  ref: z.string().optional(),
  journal_id: z.string().uuid(),
  notes: z.string().optional(),
});

const updatePaymentSchema = z.object({
  partner_id: z.string().uuid().optional(),
  payment_method: z.enum(['cash', 'bank_transfer', 'check', 'card', 'other']).optional(),
  amount: z.number().positive().optional(),
  currency_id: z.string().uuid().optional(),
  payment_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  ref: z.string().optional().nullable(),
  journal_id: z.string().uuid().optional(),
  notes: z.string().optional().nullable(),
});

const reconcilePaymentSchema = z.object({
  invoices: z.array(z.object({
    invoice_id: z.string().uuid(),
    amount: z.number().positive(),
  })).min(1),
});

const paymentQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  partner_id: z.string().uuid().optional(),
  payment_type: z.enum(['inbound', 'outbound']).optional(),
  payment_method: z.enum(['cash', 'bank_transfer', 'check', 'card', 'other']).optional(),
  status: z.enum(['draft', 'posted', 'reconciled', 'cancelled']).optional(),
  date_from: z.string().optional(),
  date_to: z.string().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

// ========== TAX SCHEMAS ==========
const createTaxSchema = z.object({
  company_id: z.string().uuid(),
  name: z.string().min(1).max(100),
  code: z.string().min(1).max(20),
  tax_type: z.enum(['sales', 'purchase', 'all']),
  amount: z.number().min(0).max(100),
  included_in_price: z.boolean().default(false),
});

const updateTaxSchema = z.object({
  name: z.string().min(1).max(100).optional(),
  code: z.string().min(1).max(20).optional(),
  tax_type: z.enum(['sales', 'purchase', 'all']).optional(),
  amount: z.number().min(0).max(100).optional(),
  included_in_price: z.boolean().optional(),
  active: z.boolean().optional(),
});

const taxQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  tax_type: z.enum(['sales', 'purchase', 'all']).optional(),
  active: z.coerce.boolean().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

class FinancialController {
  // ========== ACCOUNT TYPES ==========
  async getAccountTypes(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const accountTypes = await accountsService.findAllAccountTypes();
      res.json({ success: true, data: accountTypes });
    } catch (error) {
      next(error);
    }
  }

  // ========== ACCOUNTS ==========
  async getAccounts(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = accountQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }
      const filters: AccountFilters = queryResult.data;
      const result = await accountsService.findAll(req.tenantId!, filters);
      res.json({
        success: true,
        data: result.data,
        meta: { total: result.total, page: filters.page, limit: filters.limit, totalPages: Math.ceil(result.total / (filters.limit || 50)) },
      });
    } catch (error) {
      next(error);
    }
  }

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

  async createAccount(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createAccountSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de cuenta inválidos', parseResult.error.errors);
      }
      const dto: CreateAccountDto = parseResult.data;
      const account = await accountsService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: account, message: 'Cuenta creada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateAccount(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateAccountSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de cuenta inválidos', parseResult.error.errors);
      }
      const dto: UpdateAccountDto = parseResult.data;
      const account = await accountsService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: account, message: 'Cuenta actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async deleteAccount(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await accountsService.delete(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, message: 'Cuenta eliminada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

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

  // ========== JOURNALS ==========
  async getJournals(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = journalQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }
      const filters: JournalFilters = queryResult.data;
      const result = await journalsService.findAll(req.tenantId!, filters);
      res.json({
        success: true,
        data: result.data,
        meta: { total: result.total, page: filters.page, limit: filters.limit, totalPages: Math.ceil(result.total / (filters.limit || 50)) },
      });
    } catch (error) {
      next(error);
    }
  }

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

  async createJournal(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createJournalSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de diario inválidos', parseResult.error.errors);
      }
      const dto: CreateJournalDto = parseResult.data;
      const journal = await journalsService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: journal, message: 'Diario creado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateJournal(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateJournalSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de diario inválidos', parseResult.error.errors);
      }
      const dto: UpdateJournalDto = parseResult.data;
      const journal = await journalsService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: journal, message: 'Diario actualizado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async deleteJournal(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await journalsService.delete(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, message: 'Diario eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== JOURNAL ENTRIES ==========
  async getJournalEntries(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = journalEntryQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }
      const filters: JournalEntryFilters = queryResult.data;
      const result = await journalEntriesService.findAll(req.tenantId!, filters);
      res.json({
        success: true,
        data: result.data,
        meta: { total: result.total, page: filters.page, limit: filters.limit, totalPages: Math.ceil(result.total / (filters.limit || 20)) },
      });
    } catch (error) {
      next(error);
    }
  }

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

  async createJournalEntry(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createJournalEntrySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de póliza inválidos', parseResult.error.errors);
      }
      const dto: CreateJournalEntryDto = parseResult.data;
      const entry = await journalEntriesService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: entry, message: 'Póliza creada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateJournalEntry(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateJournalEntrySchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de póliza inválidos', parseResult.error.errors);
      }
      const dto: UpdateJournalEntryDto = parseResult.data;
      const entry = await journalEntriesService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: entry, message: 'Póliza actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async postJournalEntry(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const entry = await journalEntriesService.post(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: entry, message: 'Póliza publicada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async cancelJournalEntry(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const entry = await journalEntriesService.cancel(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: entry, message: 'Póliza cancelada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async deleteJournalEntry(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await journalEntriesService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Póliza eliminada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== INVOICES ==========
  async getInvoices(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = invoiceQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }
      const filters: InvoiceFilters = queryResult.data;
      const result = await invoicesService.findAll(req.tenantId!, filters);
      res.json({
        success: true,
        data: result.data,
        meta: { total: result.total, page: filters.page, limit: filters.limit, totalPages: Math.ceil(result.total / (filters.limit || 20)) },
      });
    } catch (error) {
      next(error);
    }
  }

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

  async createInvoice(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createInvoiceSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de factura inválidos', parseResult.error.errors);
      }
      const dto: CreateInvoiceDto = parseResult.data;
      const invoice = await invoicesService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: invoice, message: 'Factura creada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateInvoice(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateInvoiceSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de factura inválidos', parseResult.error.errors);
      }
      const dto: UpdateInvoiceDto = parseResult.data;
      const invoice = await invoicesService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: invoice, message: 'Factura actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async validateInvoice(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const invoice = await invoicesService.validate(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: invoice, message: 'Factura validada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async cancelInvoice(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const invoice = await invoicesService.cancel(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: invoice, message: 'Factura cancelada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

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

  // ========== INVOICE LINES ==========
  async addInvoiceLine(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createInvoiceLineSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de línea inválidos', parseResult.error.errors);
      }
      const dto: CreateInvoiceLineDto = parseResult.data;
      const line = await invoicesService.addLine(req.params.id, dto, req.tenantId!);
      res.status(201).json({ success: true, data: line, message: 'Línea agregada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateInvoiceLine(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateInvoiceLineSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de línea inválidos', parseResult.error.errors);
      }
      const dto: UpdateInvoiceLineDto = parseResult.data;
      const line = await invoicesService.updateLine(req.params.id, req.params.lineId, dto, req.tenantId!);
      res.json({ success: true, data: line, message: 'Línea actualizada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async removeInvoiceLine(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await invoicesService.removeLine(req.params.id, req.params.lineId, req.tenantId!);
      res.json({ success: true, message: 'Línea eliminada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== PAYMENTS ==========
  async getPayments(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = paymentQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }
      const filters: PaymentFilters = queryResult.data;
      const result = await paymentsService.findAll(req.tenantId!, filters);
      res.json({
        success: true,
        data: result.data,
        meta: { total: result.total, page: filters.page, limit: filters.limit, totalPages: Math.ceil(result.total / (filters.limit || 20)) },
      });
    } catch (error) {
      next(error);
    }
  }

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

  async createPayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createPaymentSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de pago inválidos', parseResult.error.errors);
      }
      const dto: CreatePaymentDto = parseResult.data;
      const payment = await paymentsService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: payment, message: 'Pago creado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updatePayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updatePaymentSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de pago inválidos', parseResult.error.errors);
      }
      const dto: UpdatePaymentDto = parseResult.data;
      const payment = await paymentsService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: payment, message: 'Pago actualizado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async postPayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const payment = await paymentsService.post(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: payment, message: 'Pago publicado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async reconcilePayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = reconcilePaymentSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de conciliación inválidos', parseResult.error.errors);
      }
      const dto: ReconcileDto = parseResult.data;
      const payment = await paymentsService.reconcile(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: payment, message: 'Pago conciliado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async cancelPayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const payment = await paymentsService.cancel(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: payment, message: 'Pago cancelado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async deletePayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await paymentsService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Pago eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== TAXES ==========
  async getTaxes(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = taxQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }
      const filters: TaxFilters = queryResult.data;
      const result = await taxesService.findAll(req.tenantId!, filters);
      res.json({
        success: true,
        data: result.data,
        meta: { total: result.total, page: filters.page, limit: filters.limit, totalPages: Math.ceil(result.total / (filters.limit || 20)) },
      });
    } catch (error) {
      next(error);
    }
  }

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

  async createTax(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createTaxSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de impuesto inválidos', parseResult.error.errors);
      }
      const dto: CreateTaxDto = parseResult.data;
      const tax = await taxesService.create(dto, req.tenantId!, req.user!.userId);
      res.status(201).json({ success: true, data: tax, message: 'Impuesto creado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async updateTax(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateTaxSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de impuesto inválidos', parseResult.error.errors);
      }
      const dto: UpdateTaxDto = parseResult.data;
      const tax = await taxesService.update(req.params.id, dto, req.tenantId!, req.user!.userId);
      res.json({ success: true, data: tax, message: 'Impuesto actualizado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async deleteTax(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await taxesService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Impuesto eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }
}

export const financialController = new FinancialController();
