/**
 * Transactions Controller
 *
 * REST API endpoints for payment transactions
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { TransactionsService } from '../services';
import { ProcessPaymentDto, ProcessRefundDto, SendReceiptDto, TransactionFilterDto } from '../dto';

// Extend Request to include tenant info
interface AuthenticatedRequest extends Request {
  tenantId?: string;
  userId?: string;
}

export class TransactionsController {
  public router: Router;
  private service: TransactionsService;

  constructor(dataSource: DataSource) {
    this.router = Router();
    this.service = new TransactionsService(dataSource);
    this.initializeRoutes();
  }

  private initializeRoutes(): void {
    // Stats
    this.router.get('/stats', this.getStats.bind(this));

    // Payment processing
    this.router.post('/charge', this.processPayment.bind(this));
    this.router.post('/refund', this.processRefund.bind(this));

    // Transaction queries
    this.router.get('/', this.getAll.bind(this));
    this.router.get('/:id', this.getById.bind(this));

    // Actions
    this.router.post('/:id/receipt', this.sendReceipt.bind(this));
  }

  /**
   * GET /payment-transactions/stats
   * Get transaction statistics
   */
  private async getStats(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const filter: TransactionFilterDto = {
        branchId: req.query.branchId as string,
        startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined,
        endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined,
      };

      const stats = await this.service.getStats(req.tenantId!, filter);
      res.json({ data: stats });
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /payment-transactions/charge
   * Process a payment
   */
  private async processPayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const dto: ProcessPaymentDto = req.body;
      const result = await this.service.processPayment(req.tenantId!, req.userId!, dto);

      if (result.success) {
        res.status(201).json({ data: result });
      } else {
        res.status(400).json({ data: result });
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /payment-transactions/refund
   * Process a refund
   */
  private async processRefund(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const dto: ProcessRefundDto = req.body;
      const result = await this.service.processRefund(req.tenantId!, req.userId!, dto);

      if (result.success) {
        res.json({ data: result });
      } else {
        res.status(400).json({ data: result });
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /payment-transactions
   * Get transactions with filters
   */
  private async getAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const filter: TransactionFilterDto = {
        branchId: req.query.branchId as string,
        userId: req.query.userId as string,
        status: req.query.status as any,
        sourceType: req.query.sourceType as any,
        terminalProvider: req.query.terminalProvider as string,
        startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined,
        endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined,
        limit: req.query.limit ? parseInt(req.query.limit as string) : undefined,
        offset: req.query.offset ? parseInt(req.query.offset as string) : undefined,
      };

      const result = await this.service.findAll(req.tenantId!, filter);
      res.json(result);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /payment-transactions/:id
   * Get transaction by ID
   */
  private async getById(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const transaction = await this.service.findById(req.params.id, req.tenantId!);

      if (!transaction) {
        res.status(404).json({ error: 'Transaction not found' });
        return;
      }

      res.json({ data: transaction });
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /payment-transactions/:id/receipt
   * Send receipt for transaction
   */
  private async sendReceipt(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const dto: SendReceiptDto = req.body;
      const result = await this.service.sendReceipt(req.params.id, req.tenantId!, dto);

      if (result.success) {
        res.json({ success: true });
      } else {
        res.status(400).json({ success: false, error: result.error });
      }
    } catch (error) {
      next(error);
    }
  }
}
