/**
 * Organization Admin Email Log Routes
 *
 * Org-scoped email delivery logs for the Company Admin dashboard, backed by the
 * existing EmailDispatch queue (one document per outgoing email). Reuses the
 * same auth + org-admin middleware and org-context scoping as the Audit Log
 * routes. Every query is scoped to req.orgContext.companyId — Company A can
 * never see Company B's emails. Super-admin sees all (bypass, unchanged pattern).
 */

import { Router, Request, Response } from 'express';
import { query, param, validationResult } from 'express-validator';
import { getModels } from '../models';
import { authenticate } from '../middleware/auth';
import { requireOrgAdmin } from '../middleware/orgAdmin';
import { asyncHandler } from '../middleware/errorHandler';
import { logAudit } from '../utils/auditLogger';

export const orgAdminEmailLogsRoutes = Router();

orgAdminEmailLogsRoutes.use(authenticate);
orgAdminEmailLogsRoutes.use(requireOrgAdmin);

const escapeRegex = (v: string): string => String(v || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const STATUSES = ['queued', 'sending', 'sent', 'delivered', 'opened', 'bounced', 'failed', 'cancelled'];

// ============================================
// GET / — Paginated email logs, scoped to companyId
// ============================================
orgAdminEmailLogsRoutes.get(
  '/',
  [
    query('page').optional().isInt({ min: 1 }),
    query('limit').optional().isInt({ min: 1, max: 1000 }),
    query('status').optional().isIn(STATUSES),
    query('provider').optional().trim(),
    query('sender').optional().trim(),
    query('recipient').optional().trim(),
    query('search').optional().trim(),
    query('sortBy').optional().isIn(['createdAt', 'sentAt', 'status', 'recipientEmail']),
    query('sortOrder').optional().isIn(['asc', 'desc']),
    query('startDate').optional().isISO8601(),
    query('endDate').optional().isISO8601(),
    query('export').optional().isIn(['true', 'false']),
  ],
  asyncHandler(async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    const { EmailDispatch } = getModels();
    const orgContext = req.orgContext!;
    const page = parseInt(req.query.page as string) || 1;
    const limit = parseInt(req.query.limit as string) || 20;
    const { status, provider, sender, recipient, search, startDate, endDate, sortBy, sortOrder } = req.query as Record<string, string>;

    // Org isolation: scope to company unless super-admin.
    const base: any = orgContext.isSuperAdmin ? {} : { companyId: orgContext.companyId };
    if (status) base.status = status;
    if (provider) base['payload.provider'] = { $regex: escapeRegex(provider), $options: 'i' };
    if (sender) base['payload.senderEmail'] = { $regex: escapeRegex(sender), $options: 'i' };
    if (recipient) base.recipientEmail = { $regex: escapeRegex(recipient), $options: 'i' };
    if (startDate || endDate) {
      base.createdAt = {};
      if (startDate) base.createdAt.$gte = new Date(startDate);
      if (endDate) base.createdAt.$lte = new Date(endDate);
    }
    const and: any[] = [];
    if (search) {
      const rx = { $regex: escapeRegex(search), $options: 'i' };
      and.push({ $or: [{ 'payload.subject': rx }, { recipientEmail: rx }, { providerMessageId: rx }, { 'payload.senderEmail': rx }] });
    }
    const filter = and.length ? { ...base, $and: and } : base;

    const sortField = ['createdAt', 'sentAt', 'status', 'recipientEmail'].includes(sortBy) ? sortBy : 'createdAt';
    const sortDir = sortOrder === 'asc' ? 1 : -1;

    const skip = (page - 1) * limit;
    const [rows, total] = await Promise.all([
      // Exclude the heavy HTML body from the list (loaded in the detail view).
      EmailDispatch.find(filter).select('-payload.htmlContent').sort({ [sortField]: sortDir }).skip(skip).limit(limit).lean(),
      EmailDispatch.countDocuments(filter),
    ]);

    const logs = rows.map((r: any) => ({ ...r, id: r._id?.toString?.() || r._id }));

    // Audit the export action (list fetch used for CSV/Excel/PDF).
    if (req.query.export === 'true') {
      const user = (req as any).user;
      void logAudit({
        userId: user?._id?.toString?.() || user?.id || 'unknown',
        userEmail: user?.email,
        action: 'email-logs.export',
        resource: 'EmailLog',
        companyId: orgContext.isSuperAdmin ? undefined : orgContext.companyId,
        details: { count: logs.length, filters: { status, provider, sender, recipient, search, startDate, endDate } },
        req,
      });
    }

    res.json({ logs, total, page, totalPages: Math.ceil(total / limit) });
  })
);

// ============================================
// GET /:id — single email log (full detail, org-scoped)
// ============================================
orgAdminEmailLogsRoutes.get(
  '/:id',
  [param('id').isMongoId()],
  asyncHandler(async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Invalid id' });
      return;
    }
    const { EmailDispatch } = getModels();
    const orgContext = req.orgContext!;
    const scope: any = orgContext.isSuperAdmin ? { _id: req.params.id } : { _id: req.params.id, companyId: orgContext.companyId };
    const doc = await EmailDispatch.findOne(scope).lean();
    if (!doc) {
      // 404 (not 403) so an id from another org cannot be enumerated.
      res.status(404).json({ error: 'Email log not found' });
      return;
    }
    res.json({ data: { ...doc, id: (doc as any)._id?.toString?.() || (doc as any)._id } });
  })
);

export default orgAdminEmailLogsRoutes;
