/**
 * Payment Method Controller
 * API endpoints for payment method management
 *
 * @module BillingUsage
 * @prefix /api/v1/billing/payment-methods
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  PaymentMethodService,
  CreatePaymentMethodDto,
  UpdatePaymentMethodDto,
} from '../services/payment-method.service';

const router = Router();
const paymentMethodService = new PaymentMethodService();

/**
 * GET /api/v1/billing/payment-methods
 * List all payment methods
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { provider, methodType, isActive, isDefault } = req.query;

    const methods = await paymentMethodService.findAll(
      { tenantId },
      {
        provider: provider as any,
        methodType: methodType as any,
        isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
        isDefault: isDefault === 'true' ? true : isDefault === 'false' ? false : undefined,
      }
    );

    return res.json({
      success: true,
      data: methods,
      count: methods.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/payment-methods/default
 * Get default payment method
 */
router.get('/default', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const method = await paymentMethodService.findDefault({ tenantId });
    if (!method) {
      return res.status(404).json({ error: 'No default payment method found' });
    }

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/payment-methods/stats
 * Get payment method statistics
 */
router.get('/stats', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const stats = await paymentMethodService.getPaymentMethodStats({ tenantId });

    return res.json({ success: true, data: stats });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/payment-methods/expiring
 * Get expiring cards
 */
router.get('/expiring', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const months = parseInt(req.query.months as string) || 2;
    const methods = await paymentMethodService.getExpiringCards({ tenantId }, months);

    return res.json({
      success: true,
      data: methods,
      count: methods.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/billing/payment-methods/:id
 * Get payment method by ID
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const method = await paymentMethodService.findById({ tenantId }, req.params.id);
    if (!method) {
      return res.status(404).json({ error: 'Payment method not found' });
    }

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/payment-methods
 * Add a new payment method
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: CreatePaymentMethodDto = req.body;

    if (!data.provider || !data.methodType) {
      return res.status(400).json({ error: 'provider and methodType are required' });
    }

    const method = await paymentMethodService.create({ tenantId }, data);
    return res.status(201).json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/billing/payment-methods/:id
 * Update a payment method
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: UpdatePaymentMethodDto = req.body;
    const method = await paymentMethodService.update({ tenantId }, req.params.id, data);

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

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/payment-methods/:id/set-default
 * Set payment method as default
 */
router.post('/:id/set-default', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const method = await paymentMethodService.setAsDefault({ tenantId }, req.params.id);

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

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/payment-methods/:id/verify
 * Verify a payment method
 */
router.post('/:id/verify', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const method = await paymentMethodService.verify({ tenantId }, req.params.id);

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

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/payment-methods/:id/deactivate
 * Deactivate a payment method
 */
router.post('/:id/deactivate', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const method = await paymentMethodService.deactivate({ tenantId }, req.params.id);

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

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/billing/payment-methods/:id
 * Delete a payment method
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const deleted = await paymentMethodService.delete({ tenantId }, req.params.id);
    if (!deleted) {
      return res.status(404).json({ error: 'Payment method not found' });
    }

    return res.json({ success: true, message: 'Payment method deleted' });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/billing/payment-methods/sync-from-provider
 * Sync payment method details from provider
 */
router.post('/sync-from-provider', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { providerMethodId, cardBrand, cardLastFour, cardExpMonth, cardExpYear } = req.body;

    if (!providerMethodId) {
      return res.status(400).json({ error: 'providerMethodId is required' });
    }

    const method = await paymentMethodService.updateFromProvider(
      { tenantId },
      providerMethodId,
      {
        cardBrand,
        cardLastFour,
        cardExpMonth,
        cardExpYear,
      }
    );

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

    return res.json({ success: true, data: method });
  } catch (error) {
    return next(error);
  }
});

export default router;
