/**
 * Billing Alert Controller
 * API endpoints for billing alerts management
 *
 * @module BillingUsage
 * @prefix /api/v1/billing/alerts
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  BillingAlertService,
  CreateBillingAlertDto,
  UpdateBillingAlertDto,
} from '../services/billing-alert.service';

const router = Router();
const alertService = new BillingAlertService();

/**
 * GET /api/v1/billing/alerts
 * List all billing alerts
 */
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 { alertType, severity, status } = req.query;

    const alerts = await alertService.findAll(
      { tenantId },
      {
        alertType: alertType as any,
        severity: severity as any,
        status: status as any,
      }
    );

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

/**
 * GET /api/v1/billing/alerts/active
 * Get active alerts
 */
router.get('/active', 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 alerts = await alertService.getActiveAlerts({ tenantId });

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

/**
 * GET /api/v1/billing/alerts/unacknowledged
 * Get unacknowledged alerts
 */
router.get('/unacknowledged', 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 alerts = await alertService.getUnacknowledgedAlerts({ tenantId });

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

/**
 * GET /api/v1/billing/alerts/counts
 * Get alert counts by status, severity, and type
 */
router.get('/counts', 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 counts = await alertService.getAlertCounts({ tenantId });

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

/**
 * GET /api/v1/billing/alerts/:id
 * Get alert 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 alert = await alertService.findById({ tenantId }, req.params.id);
    if (!alert) {
      return res.status(404).json({ error: 'Alert not found' });
    }

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

/**
 * POST /api/v1/billing/alerts
 * Create a new alert
 */
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: CreateBillingAlertDto = req.body;

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

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

/**
 * POST /api/v1/billing/alerts/usage-limit
 * Create a usage limit alert
 */
router.post('/usage-limit', 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 { limitType, currentUsage, limit, percentUsed } = req.body;

    if (!limitType || currentUsage === undefined || limit === undefined || percentUsed === undefined) {
      return res.status(400).json({
        error: 'limitType, currentUsage, limit, and percentUsed are required',
      });
    }

    const alert = await alertService.createUsageLimitAlert(
      { tenantId },
      limitType,
      currentUsage,
      limit,
      percentUsed
    );

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

/**
 * POST /api/v1/billing/alerts/payment-due
 * Create a payment due alert
 */
router.post('/payment-due', 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 { dueDate, amount } = req.body;

    if (!dueDate || amount === undefined) {
      return res.status(400).json({ error: 'dueDate and amount are required' });
    }

    const alert = await alertService.createPaymentDueAlert(
      { tenantId },
      new Date(dueDate),
      amount
    );

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

/**
 * POST /api/v1/billing/alerts/payment-failed
 * Create a payment failed alert
 */
router.post('/payment-failed', 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 { amount, errorMessage } = req.body;

    if (amount === undefined || !errorMessage) {
      return res.status(400).json({ error: 'amount and errorMessage are required' });
    }

    const alert = await alertService.createPaymentFailedAlert(
      { tenantId },
      amount,
      errorMessage
    );

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

/**
 * POST /api/v1/billing/alerts/trial-ending
 * Create a trial ending alert
 */
router.post('/trial-ending', 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 { trialEndDate } = req.body;

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

    const alert = await alertService.createTrialEndingAlert(
      { tenantId },
      new Date(trialEndDate)
    );

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

/**
 * PATCH /api/v1/billing/alerts/:id
 * Update an alert
 */
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: UpdateBillingAlertDto = req.body;
    const alert = await alertService.update({ tenantId }, req.params.id, data);

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

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

/**
 * POST /api/v1/billing/alerts/:id/acknowledge
 * Acknowledge an alert
 */
router.post('/:id/acknowledge', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    const userId = (req as any).user?.id;

    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const alert = await alertService.acknowledge({ tenantId, userId }, req.params.id);

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

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

/**
 * POST /api/v1/billing/alerts/:id/resolve
 * Resolve an alert
 */
router.post('/:id/resolve', 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 alert = await alertService.resolve({ tenantId }, req.params.id);

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

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

/**
 * POST /api/v1/billing/alerts/:id/notify
 * Mark alert as notified
 */
router.post('/:id/notify', 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 alert = await alertService.markAsNotified({ tenantId }, req.params.id);

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

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

/**
 * POST /api/v1/billing/alerts/resolve-by-type
 * Resolve all alerts of a specific type
 */
router.post('/resolve-by-type', 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 { alertType } = req.body;

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

    const count = await alertService.resolveAlertsByType({ tenantId }, alertType);

    return res.json({
      success: true,
      message: `Resolved ${count} alerts`,
      count,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/billing/alerts/:id
 * Delete an alert
 */
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 alertService.delete({ tenantId }, req.params.id);
    if (!deleted) {
      return res.status(404).json({ error: 'Alert not found' });
    }

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

export default router;
