/**
 * FiscalCalculationController - Controller de Calculos Fiscales
 *
 * Endpoints REST para calculos de impuestos y retenciones.
 *
 * @module Fiscal
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { FiscalCalculationService, TaxCalculationInput } from '../services/fiscal-calculation.service';
import { AuthMiddleware } from '../../auth/middleware/auth.middleware';
import { AuthService } from '../../auth/services/auth.service';
import { TaxCategory } from '../entities/tax-category.entity';
import { WithholdingType } from '../entities/withholding-type.entity';
import { User } from '../../core/entities/user.entity';
import { Tenant } from '../../core/entities/tenant.entity';
import { RefreshToken } from '../../auth/entities/refresh-token.entity';

interface ServiceContext {
  tenantId: string;
  userId?: string;
}

export function createFiscalCalculationController(dataSource: DataSource): Router {
  const router = Router();

  // Repositories
  const taxCategoryRepository = dataSource.getRepository(TaxCategory);
  const withholdingTypeRepository = dataSource.getRepository(WithholdingType);
  const userRepository = dataSource.getRepository(User);
  const tenantRepository = dataSource.getRepository(Tenant);
  const refreshTokenRepository = dataSource.getRepository(RefreshToken);

  // Services
  const fiscalCalculationService = new FiscalCalculationService(
    taxCategoryRepository,
    withholdingTypeRepository
  );
  const authService = new AuthService(userRepository, tenantRepository, refreshTokenRepository as any);
  const authMiddleware = new AuthMiddleware(authService, dataSource);

  // Helper to create context
  const getContext = (req: Request): ServiceContext => {
    if (!req.tenantId) {
      throw new Error('Tenant ID is required');
    }
    return {
      tenantId: req.tenantId,
      userId: req.user?.sub,
    };
  };

  /**
   * POST /fiscal-calculations/taxes
   * Calculate taxes and withholdings for an amount
   */
  router.post('/taxes', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const input: TaxCalculationInput = req.body;
      if (input.subtotal === undefined || !input.taxRates || !Array.isArray(input.taxRates)) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'subtotal and taxRates array are required',
        });
        return;
      }

      const result = await fiscalCalculationService.calculateTaxes(getContext(req), input);
      res.status(200).json({ success: true, data: result });
    } catch (error) {
      if (error instanceof Error && error.message.includes('not found')) {
        res.status(404).json({ error: 'Not Found', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * POST /fiscal-calculations/iva
   * Calculate IVA for an amount
   */
  router.post('/iva', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { amount, rate } = req.body;
      if (amount === undefined) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'amount is required',
        });
        return;
      }

      const result = rate !== undefined
        ? fiscalCalculationService.calculateIVA(getContext(req), amount, rate)
        : fiscalCalculationService.calculateStandardIVA(getContext(req), amount);

      res.status(200).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /fiscal-calculations/isr-withholding
   * Calculate ISR withholding for an amount
   */
  router.post('/isr-withholding', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { amount, rate } = req.body;
      if (amount === undefined) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'amount is required',
        });
        return;
      }

      const result = fiscalCalculationService.calculateISRWithholding(getContext(req), amount, rate);
      res.status(200).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /fiscal-calculations/iva-withholding
   * Calculate IVA withholding for an amount
   */
  router.post('/iva-withholding', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { amount, rate } = req.body;
      if (amount === undefined) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'amount is required',
        });
        return;
      }

      const result = fiscalCalculationService.calculateIVAWithholding(getContext(req), amount, rate);
      res.status(200).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /fiscal-calculations/invoice-total
   * Calculate complete invoice total with taxes and withholdings
   */
  router.post('/invoice-total', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { subtotal, ivaRate, isrWithholdingRate, ivaWithholdingRate } = req.body;
      if (subtotal === undefined) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'subtotal is required',
        });
        return;
      }

      const result = fiscalCalculationService.calculateInvoiceTotal(
        getContext(req),
        subtotal,
        ivaRate,
        isrWithholdingRate,
        ivaWithholdingRate
      );

      res.status(200).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /fiscal-calculations/base-from-total
   * Get base amount from total including IVA
   */
  router.post('/base-from-total', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { totalWithIVA, ivaRate } = req.body;
      if (totalWithIVA === undefined) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'totalWithIVA is required',
        });
        return;
      }

      const base = fiscalCalculationService.getBaseFromTotalWithIVA(getContext(req), totalWithIVA, ivaRate);
      res.status(200).json({ success: true, data: { base, totalWithIVA, ivaRate: ivaRate ?? 16 } });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /fiscal-calculations/validate
   * Validate fiscal calculation
   */
  router.post('/validate', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { subtotal, expectedTotal, ivaRate, tolerance } = req.body;
      if (subtotal === undefined || expectedTotal === undefined) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'subtotal and expectedTotal are required',
        });
        return;
      }

      const result = fiscalCalculationService.validateCalculation(
        getContext(req),
        subtotal,
        expectedTotal,
        ivaRate,
        tolerance
      );

      res.status(200).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  });

  return router;
}

export default createFiscalCalculationController;
