/**
 * WhatsApp Broadcast Controller
 * API endpoints for broadcast campaign management
 *
 * @module WhatsApp
 * @prefix /api/v1/whatsapp/broadcasts
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  BroadcastService,
  CreateBroadcastDto,
  UpdateBroadcastDto,
  AddRecipientDto,
  ServiceContext,
} from '../services';

const router = Router();
const broadcastService = new BroadcastService();

function getServiceContext(req: Request): ServiceContext {
  const tenantId = req.headers['x-tenant-id'] as string;
  const userId = (req as any).user?.id;
  return { tenantId, userId };
}

/**
 * GET /api/v1/whatsapp/broadcasts
 * List all broadcasts
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { accountId, status, audienceType, page, limit } = req.query;

    const result = await broadcastService.findAll(
      ctx,
      {
        accountId: accountId as string,
        status: status as any,
        audienceType: audienceType as any,
      },
      {
        page: page ? parseInt(page as string) : undefined,
        limit: limit ? parseInt(limit as string) : undefined,
      }
    );

    return res.json({
      success: true,
      data: result.data,
      total: result.total,
      page: page ? parseInt(page as string) : 1,
      limit: limit ? parseInt(limit as string) : 50,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/whatsapp/broadcasts/scheduled
 * Get scheduled broadcasts
 */
router.get('/scheduled', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const broadcasts = await broadcastService.findScheduled(ctx);
    return res.json({ success: true, data: broadcasts, count: broadcasts.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/whatsapp/broadcasts/statistics
 * Get broadcast statistics
 */
router.get('/statistics', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { accountId } = req.query;
    const stats = await broadcastService.getStatistics(ctx, accountId as string);
    return res.json({ success: true, data: stats });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/whatsapp/broadcasts/:id
 * Get broadcast by ID
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const broadcast = await broadcastService.findById(ctx, req.params.id);
    if (!broadcast) {
      return res.status(404).json({ error: 'Broadcast not found' });
    }

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

/**
 * GET /api/v1/whatsapp/broadcasts/:id/recipients
 * Get broadcast recipients
 */
router.get('/:id/recipients', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { status, page, limit } = req.query;

    const result = await broadcastService.getRecipients(
      req.params.id,
      status as any,
      {
        page: page ? parseInt(page as string) : undefined,
        limit: limit ? parseInt(limit as string) : undefined,
      }
    );

    return res.json({
      success: true,
      data: result.data,
      total: result.total,
      page: page ? parseInt(page as string) : 1,
      limit: limit ? parseInt(limit as string) : 50,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts
 * Create a new broadcast
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: CreateBroadcastDto = req.body;

    if (!data.accountId || !data.name || !data.templateId || !data.audienceType) {
      return res.status(400).json({
        error: 'accountId, name, templateId, and audienceType are required',
      });
    }

    const validAudienceTypes = ['all', 'segment', 'custom', 'file'];
    if (!validAudienceTypes.includes(data.audienceType)) {
      return res.status(400).json({
        error: `audienceType must be one of: ${validAudienceTypes.join(', ')}`,
      });
    }

    const broadcast = await broadcastService.create(ctx, data);
    return res.status(201).json({ success: true, data: broadcast });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/whatsapp/broadcasts/:id
 * Update broadcast
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: UpdateBroadcastDto = req.body;
    const broadcast = await broadcastService.update(ctx, req.params.id, data);

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

    return res.json({ success: true, data: broadcast });
  } catch (error: any) {
    if (error.message?.includes('Cannot update')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts/:id/recipients
 * Add recipient to broadcast
 */
router.post('/:id/recipients', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: AddRecipientDto = req.body;

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

    const recipient = await broadcastService.addRecipient(ctx, req.params.id, data);
    return res.status(201).json({ success: true, data: recipient });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts/:id/recipients/bulk
 * Add multiple recipients to broadcast
 */
router.post('/:id/recipients/bulk', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { recipients } = req.body;

    if (!recipients || !Array.isArray(recipients)) {
      return res.status(400).json({ error: 'recipients array is required' });
    }

    const count = await broadcastService.addRecipients(ctx, req.params.id, recipients);
    return res.json({ success: true, data: { addedCount: count } });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/whatsapp/broadcasts/:id/recipients/:recipientId
 * Remove recipient from broadcast
 */
router.delete('/:id/recipients/:recipientId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const removed = await broadcastService.removeRecipient(
      ctx,
      req.params.id,
      req.params.recipientId
    );

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

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

/**
 * POST /api/v1/whatsapp/broadcasts/:id/schedule
 * Schedule broadcast
 */
router.post('/:id/schedule', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { scheduledAt } = req.body;

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

    const scheduleDate = new Date(scheduledAt);
    if (scheduleDate <= new Date()) {
      return res.status(400).json({ error: 'scheduledAt must be in the future' });
    }

    const broadcast = await broadcastService.schedule(ctx, req.params.id, scheduleDate);
    if (!broadcast) {
      return res.status(404).json({ error: 'Broadcast not found' });
    }

    return res.json({ success: true, data: broadcast });
  } catch (error: any) {
    if (error.message?.includes('Cannot schedule')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts/:id/start
 * Start broadcast immediately
 */
router.post('/:id/start', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const broadcast = await broadcastService.start(ctx, req.params.id);
    if (!broadcast) {
      return res.status(404).json({ error: 'Broadcast not found' });
    }

    return res.json({ success: true, data: broadcast });
  } catch (error: any) {
    if (error.message?.includes('Cannot start')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts/:id/cancel
 * Cancel broadcast
 */
router.post('/:id/cancel', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const broadcast = await broadcastService.cancel(ctx, req.params.id);
    if (!broadcast) {
      return res.status(404).json({ error: 'Broadcast not found' });
    }

    return res.json({ success: true, data: broadcast });
  } catch (error: any) {
    if (error.message?.includes('Cannot cancel')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts/:id/estimate-cost
 * Estimate broadcast cost
 */
router.post('/:id/estimate-cost', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { costPerMessage } = req.body;

    if (costPerMessage === undefined || costPerMessage < 0) {
      return res.status(400).json({ error: 'costPerMessage is required and must be non-negative' });
    }

    const estimatedCost = await broadcastService.estimateCost(ctx, req.params.id, costPerMessage);
    return res.json({ success: true, data: { estimatedCost } });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/whatsapp/broadcasts/:id/duplicate
 * Duplicate broadcast
 */
router.post('/:id/duplicate', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { name } = req.body;

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

    const broadcast = await broadcastService.duplicate(ctx, req.params.id, name);
    if (!broadcast) {
      return res.status(404).json({ error: 'Broadcast not found' });
    }

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

/**
 * DELETE /api/v1/whatsapp/broadcasts/:id
 * Delete broadcast
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const ctx = getServiceContext(req);
    if (!ctx.tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const deleted = await broadcastService.delete(ctx, req.params.id);
    if (!deleted) {
      return res.status(404).json({ error: 'Broadcast not found' });
    }

    return res.json({ success: true, message: 'Broadcast deleted' });
  } catch (error: any) {
    if (error.message?.includes('Cannot delete')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

export default router;
