import { Request, Response } from 'express';
import { assignmentService } from '../services/assignment.service';
import { rbacService, Permission } from '../services/rbac.service';

/**
 * Assignment Controller
 * Handles all assignment-related HTTP requests
 */
export class AssignmentController {
  /**
   * Assign a task to a user
   */
  async assignTask(req: Request, res: Response): Promise<void> {
    try {
      const { taskId, assigneeId, dueDate, workloadPoints, notes } = req.body;
      const assignerId = req.userId!;

      const assignment = await assignmentService.assignTask(
        taskId,
        assigneeId,
        assignerId,
        { dueDate, workloadPoints, notes }
      );

      res.status(201).json({
        success: true,
        data: assignment
      });
    } catch (error: any) {
      res.status(error.message.includes('Permission') ? 403 : 400).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Reassign a task to a different user
   */
  async reassignTask(req: Request, res: Response): Promise<void> {
    try {
      const { taskId, newAssigneeId, reason } = req.body;
      const reassignerId = req.userId!;

      const assignment = await assignmentService.reassignTask(
        taskId,
        newAssigneeId,
        reassignerId,
        reason
      );

      res.json({
        success: true,
        data: assignment
      });
    } catch (error: any) {
      res.status(error.message.includes('Permission') ? 403 : 400).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Unassign a task
   */
  async unassignTask(req: Request, res: Response): Promise<void> {
    try {
      const { taskId } = req.params;
      const unassignerId = req.userId!;

      await assignmentService.unassignTask(taskId, unassignerId);

      res.json({
        success: true,
        message: 'Task unassigned successfully'
      });
    } catch (error: any) {
      res.status(error.message.includes('Permission') ? 403 : 400).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Get tasks assigned to a user
   */
  async getAssignedTasks(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params;
      const requesterId = req.userId!;
      
      // Check if user can view other user's tasks
      if (userId !== requesterId) {
        const canViewUsers = await rbacService.hasPermission(
          requesterId,
          Permission.VIEW_USERS
        );
        
        if (!canViewUsers) {
          res.status(403).json({
            success: false,
            error: 'Permission denied: Cannot view other users\' tasks'
          });
          return;
        }
      }

      const options = {
        includeCompleted: req.query.includeCompleted === 'true',
        projectId: req.query.projectId as string | undefined,
        status: req.query.status as string | undefined,
        sort: req.query.sort as string | undefined,
        limit: req.query.limit ? parseInt(req.query.limit as string) : undefined
      };

      const tasks = await assignmentService.getAssignedTasks(userId, options);

      res.json({
        success: true,
        data: tasks
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Get workload summary for a user
   */
  async getWorkloadSummary(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params;
      const requesterId = req.userId!;
      
      // Check if user can view other user's workload
      if (userId !== requesterId) {
        const canViewUsers = await rbacService.hasPermission(
          requesterId,
          Permission.VIEW_USERS
        );
        
        if (!canViewUsers) {
          res.status(403).json({
            success: false,
            error: 'Permission denied: Cannot view other users\' workload'
          });
          return;
        }
      }

      const summary = await assignmentService.getWorkloadSummary(userId);

      res.json({
        success: true,
        data: summary
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Get assignment recommendations for a task
   */
  async getAssignmentRecommendations(req: Request, res: Response): Promise<void> {
    try {
      const { taskId } = req.params;
      const options = {
        maxRecommendations: req.query.maxRecommendations 
          ? parseInt(req.query.maxRecommendations as string) 
          : undefined,
        projectTeamOnly: req.query.projectTeamOnly === 'true'
      };

      const recommendations = await assignmentService.getAssignmentRecommendations(
        taskId,
        options
      );

      res.json({
        success: true,
        data: recommendations
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Batch assign multiple tasks
   */
  async batchAssignTasks(req: Request, res: Response): Promise<void> {
    try {
      const { assignments } = req.body;
      const assignerId = req.userId!;

      const results = await assignmentService.batchAssignTasks(
        assignments,
        assignerId
      );

      res.json({
        success: true,
        data: {
          assigned: results.length,
          assignments: results
        }
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Auto-balance workload across project team
   */
  async autoBalanceWorkload(req: Request, res: Response): Promise<void> {
    try {
      const { projectId } = req.params;
      const balancerId = req.userId!;

      const result = await assignmentService.autoBalanceWorkload(
        projectId,
        balancerId
      );

      res.json({
        success: true,
        data: result
      });
    } catch (error: any) {
      res.status(error.message.includes('Permission') ? 403 : 400).json({
        success: false,
        error: error.message
      });
    }
  }
}