/**
 * Admin Feature Request Routes
 *
 * Admin-facing routes for managing feature requests.
 * Super Admins can view all requests, approve/reject/mark done, and delete.
 * Regular Admins have view-only access.
 */

import express, { Request, Response } from 'express';
import { body, param, query, validationResult } from 'express-validator';
import { authenticate, requireRole } from '../middleware/auth';
import { getModels } from '../models';
import { notifyFeatureRequestActivity } from '../services/featureRequestNotifications';

const router = express.Router();

// All routes require authentication and admin role
router.use(authenticate);
router.use(requireRole('admin', 'super-admin'));

// ============================================
// GET / — List all feature requests (with filters)
// ============================================

router.get('/',
  [
    query('page').optional().isInt({ min: 1 }).toInt(),
    query('limit').optional().isInt({ min: 1, max: 100 }).toInt(),
    query('status').optional().isIn(['Pending', 'Approved', 'Rejected', 'Done', 'Withdrawn']),
    query('priority').optional().isIn(['Low', 'Medium', 'High']),
    query('category').optional().isIn(['UI', 'AI', 'Integration', 'Other']),
    query('search').optional().trim(),
    query('companyId').optional().trim(),
  ],
  async (req: Request, res: Response) => {
    try {
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        res.status(400).json({ errors: errors.array() });
        return;
      }

      const { FeatureRequest, User, Company } = getModels();
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 20;
      const { status, priority, category, search, companyId } = req.query;

      // Build filter
      const filter: any = {};

      // Super-admin sees all, admin sees only their company's
      if (req.user!.role !== 'super-admin') {
        filter.companyId = { $in: req.user!.companyIds };
      } else if (companyId) {
        filter.companyId = companyId;
      }

      if (status) filter.status = status;
      if (priority) filter.priority = priority;
      if (category) filter.category = category;

      if (search && typeof search === 'string' && search.trim()) {
        filter.$or = [
          { title: { $regex: search.trim(), $options: 'i' } },
          { description: { $regex: search.trim(), $options: 'i' } }
        ];
      }

      const skip = (page - 1) * limit;

      const [requests, total] = await Promise.all([
        FeatureRequest.find(filter)
          .sort({ createdAt: -1 })
          .skip(skip)
          .limit(limit)
          .lean(),
        FeatureRequest.countDocuments(filter)
      ]);

      // Fetch user info for each request
      const userIds = [...new Set(requests.map((r: any) => r.userId))];
      const companyIds = [...new Set(requests.map((r: any) => r.companyId))];

      const [users, companies] = await Promise.all([
        User.find({ _id: { $in: userIds } }).select('_id name email').lean(),
        Company.find({ _id: { $in: companyIds } }).select('_id name').lean()
      ]);

      const userMap = new Map(users.map((u: any) => [u._id.toString(), u]));
      const companyMap = new Map(companies.map((c: any) => [c._id.toString(), c]));

      // Enrich requests with user and company info
      const enrichedRequests = requests.map((r: any) => ({
        ...r,
        userName: (userMap.get(r.userId) as any)?.name || 'Unknown',
        userEmail: (userMap.get(r.userId) as any)?.email || '',
        companyName: (companyMap.get(r.companyId) as any)?.name || 'Unknown'
      }));

      res.json({
        requests: enrichedRequests,
        total,
        page,
        totalPages: Math.ceil(total / limit)
      });
    } catch (error: any) {
      console.error('[AdminFeatureRequest] List error:', error.message);
      res.status(500).json({ error: 'Failed to get feature requests' });
    }
  }
);

// ============================================
// GET /:id — Get single feature request
// ============================================

router.get('/:id', async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { FeatureRequest, User, Company } = getModels();

    const request = await FeatureRequest.findById(id);
    if (!request) {
      res.status(404).json({ error: 'Feature request not found' });
      return;
    }

    // Verify admin has access to this company
    if (req.user!.role !== 'super-admin' && !req.user!.companyIds.includes(request.companyId)) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    // When a Super Admin opens/views the request, mark it as Read.
    if (req.user!.role === 'super-admin' && !request.isRead) {
      request.isRead = true;
      await request.save();
    }

    // Get user and company info
    const [user, company] = await Promise.all([
      User.findById(request.userId).select('_id name email').lean(),
      Company.findById(request.companyId).select('_id name').lean()
    ]);

    res.json({
      ...request.toObject(),
      userName: user?.name || 'Unknown',
      userEmail: user?.email || '',
      companyName: company?.name || 'Unknown'
    });
  } catch (error: any) {
    console.error('[AdminFeatureRequest] Get error:', error.message);
    res.status(500).json({ error: 'Failed to get feature request' });
  }
});

// ============================================
// PATCH /:id/status — Update status (approve/reject/mark done)
// ============================================

router.patch('/:id/status',
  [
    param('id').notEmpty().withMessage('Request ID is required'),
    body('status').isIn(['Approved', 'Rejected', 'Done']).withMessage('Invalid status. Must be Approved, Rejected, or Done'),
    body('adminNote').optional().trim().isLength({ max: 1000 }).withMessage('Admin note cannot exceed 1000 characters'),
  ],
  async (req: Request, res: Response) => {
    try {
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        res.status(400).json({ errors: errors.array() });
        return;
      }

      // Only super-admin can update status
      if (req.user!.role !== 'super-admin') {
        res.status(403).json({ error: 'Only super-admin can update status' });
        return;
      }

      const { id } = req.params;
      const { status, adminNote } = req.body;
      const { FeatureRequest } = getModels();

      const request = await FeatureRequest.findById(id);
      if (!request) {
        res.status(404).json({ error: 'Feature request not found' });
        return;
      }

      // Validate status transitions
      if (status === 'Approved' && request.status !== 'Pending') {
        res.status(400).json({ error: 'Can only approve pending requests' });
        return;
      }

      if (status === 'Rejected' && request.status !== 'Pending') {
        res.status(400).json({ error: 'Can only reject pending requests' });
        return;
      }

      if (status === 'Done' && request.status !== 'Approved') {
        res.status(400).json({ error: 'Can only mark approved requests as done' });
        return;
      }

      // Update status
      request.status = status;
      if (adminNote) request.adminNote = adminNote;
      request.updatedAt = new Date() as any;
      await request.save();

      // Notify configured recipients about the status change
      const specificActivityType = status === 'Approved' ? 'approved' : status === 'Rejected' ? 'rejected' : 'done';
      notifyFeatureRequestActivity({
        activityType: 'status_update',
        featureRequestId: (request as any)._id.toString(),
        featureRequestTitle: request.title,
        triggeredByUserId: req.user!._id.toString(),
        triggeredByUserName: (req.user as any).name || 'Unknown',
        triggeredByUserRole: req.user!.role || 'super-admin',
        details: {
          status,
          adminNote: adminNote || '',
          previousStatus: request.status === status ? '' : request.status, // already updated, so this is after-save
        },
      }).catch(() => { /* fire-and-forget */ });
      // Also send the specific activity type (approved/rejected/done)
      notifyFeatureRequestActivity({
        activityType: specificActivityType as any,
        featureRequestId: (request as any)._id.toString(),
        featureRequestTitle: request.title,
        triggeredByUserId: req.user!._id.toString(),
        triggeredByUserName: (req.user as any).name || 'Unknown',
        triggeredByUserRole: req.user!.role || 'super-admin',
        details: {
          status,
          adminNote: adminNote || '',
        },
      }).catch(() => { /* fire-and-forget */ });

      res.json({ message: 'Status updated successfully', request });
    } catch (error: any) {
      console.error('[AdminFeatureRequest] Update status error:', error.message);
      res.status(500).json({ error: 'Failed to update status' });
    }
  }
);

// ============================================
// PATCH /:id — Edit request content (Admin only, after Super Admin has read it)
// Editing marks the request Unread again so the Super Admin re-reviews it.
// ============================================

router.patch('/:id',
  [
    param('id').notEmpty().withMessage('Request ID is required'),
    body('title').optional().trim().isLength({ min: 1, max: 200 }).withMessage('Title must be 1-200 characters'),
    body('description').optional().trim().isLength({ min: 1, max: 5000 }).withMessage('Description must be 1-5000 characters'),
    body('category').optional().isIn(['UI', 'AI', 'Integration', 'Other']).withMessage('Invalid category'),
    body('priority').optional().isIn(['Low', 'Medium', 'High']).withMessage('Invalid priority'),
  ],
  async (req: Request, res: Response) => {
    try {
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        res.status(400).json({ errors: errors.array() });
        return;
      }

      // Only Admins edit requests; Super Admins review, not edit.
      if (req.user!.role !== 'admin') {
        res.status(403).json({ error: 'Only admins can edit feature requests' });
        return;
      }

      const { id } = req.params;
      const { title, description, category, priority } = req.body;
      const { FeatureRequest } = getModels();

      const request = await FeatureRequest.findById(id);
      if (!request) {
        res.status(404).json({ error: 'Feature request not found' });
        return;
      }

      // Admin can only edit requests within their own company
      if (!req.user!.companyIds.includes(request.companyId)) {
        res.status(403).json({ error: 'Access denied' });
        return;
      }

      // A request can only be edited once the Super Admin has read it.
      if (!request.isRead) {
        res.status(400).json({ error: 'Request must be reviewed by Super Admin before it can be edited' });
        return;
      }

      if (title !== undefined) request.title = title;
      if (description !== undefined) request.description = description;
      if (category !== undefined) request.category = category;
      if (priority !== undefined) request.priority = priority;

      // Modified requests go back to Unread so the Super Admin reviews them again,
      // and are flagged as Edited so the change is visible on the entry.
      request.isRead = false;
      request.isEdited = true;
      request.updatedAt = new Date() as any;
      await request.save();

      // Notify configured recipients about the admin edit
      notifyFeatureRequestActivity({
        activityType: 'edited',
        featureRequestId: (request as any)._id.toString(),
        featureRequestTitle: request.title,
        triggeredByUserId: req.user!._id.toString(),
        triggeredByUserName: (req.user as any).name || 'Unknown',
        triggeredByUserRole: req.user!.role || 'admin',
      }).catch(() => { /* fire-and-forget */ });

      res.json({ message: 'Feature request updated successfully', request });
    } catch (error: any) {
      console.error('[AdminFeatureRequest] Edit error:', error.message);
      if (error?.name === 'ValidationError') {
        const messages = Object.values(error.errors).map((e: any) => e.message);
        res.status(400).json({ error: messages.join('. ') });
        return;
      }
      res.status(500).json({ error: 'Failed to update feature request' });
    }
  }
);

// ============================================
// DELETE /:id — Delete feature request (super-admin only)
// ============================================

router.delete('/:id', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { FeatureRequest } = getModels();

    const request = await FeatureRequest.findById(id);
    if (!request) {
      res.status(404).json({ error: 'Feature request not found' });
      return;
    }

    // Capture info before deletion for notification
    const requestTitle = request.title;
    const requestId = (request as any)._id.toString();

    await FeatureRequest.findByIdAndDelete(id);

    // Notify configured recipients about the deletion
    notifyFeatureRequestActivity({
      activityType: 'deleted',
      featureRequestId: requestId,
      featureRequestTitle: requestTitle,
      triggeredByUserId: req.user!._id.toString(),
      triggeredByUserName: (req.user as any).name || 'Unknown',
      triggeredByUserRole: req.user!.role || 'super-admin',
    }).catch(() => { /* fire-and-forget */ });

    res.json({ message: 'Feature request deleted successfully' });
  } catch (error: any) {
    console.error('[AdminFeatureRequest] Delete error:', error.message);
    res.status(500).json({ error: 'Failed to delete feature request' });
  }
});

export default router;