<?php
/**
 * Assignment Service
 * 
 * This service provides methods to create and manage member assignments
 */

class AssignmentService {
    private $db;
    private $notificationService;

    public function __construct() {
        require_once __DIR__ . '/../config/database.php';
        require_once __DIR__ . '/NotificationService.php';
        $this->db = new Database();
        $this->notificationService = new NotificationService();
    }

    /**
     * Assign a member to an admin
     *
     * @param array $data Assignment data
     * @return array Result with success status and assignment ID
     */
    public function assignMember($data) {
        try {
            $conn = $this->db->getConnection();
            
            // Start transaction
            $conn->beginTransaction();
            
            // Insert assignment
            $query = "INSERT INTO admin_assignments 
                      (member_id, assigned_to, assigned_by, assignment_type, priority, due_date, status, notes) 
                      VALUES 
                      (:member_id, :assigned_to, :assigned_by, :assignment_type, :priority, :due_date, 'active', :notes)";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':member_id', $data['member_id']);
            $stmt->bindValue(':assigned_to', $data['assigned_to']);
            $stmt->bindValue(':assigned_by', $data['assigned_by']);
            $stmt->bindValue(':assignment_type', $data['assignment_type']);
            $stmt->bindValue(':priority', $data['priority']);
            $stmt->bindValue(':due_date', isset($data['due_date']) ? $data['due_date'] : null);
            $stmt->bindValue(':notes', isset($data['notes']) ? $data['notes'] : null);
            $stmt->execute();
            
            $assignmentId = $conn->lastInsertId();
            
            // Update member assigned_to field
            $updateMemberQuery = "UPDATE members 
                                 SET assigned_to = :assigned_to, 
                                     assignment_notes = :notes, 
                                     assignment_date = NOW() 
                                 WHERE id = :member_id";
            $updateMemberStmt = $conn->prepare($updateMemberQuery);
            $updateMemberStmt->bindValue(':assigned_to', $data['assigned_to']);
            $updateMemberStmt->bindValue(':notes', isset($data['notes']) ? $data['notes'] : null);
            $updateMemberStmt->bindValue(':member_id', $data['member_id']);
            $updateMemberStmt->execute();
            
            // Add to member approval history
            $historyQuery = "INSERT INTO member_approval_history 
                             (member_id, action, performed_by, from_status, to_status, assigned_from, assigned_to, notes, ip_address) 
                             VALUES 
                             (:member_id, 'assigned', :performed_by, 
                              (SELECT status FROM members WHERE id = :member_id), 
                              'under_review', 
                              NULL, :assigned_to, :notes, :ip_address)";
            $historyStmt = $conn->prepare($historyQuery);
            $historyStmt->bindValue(':member_id', $data['member_id']);
            $historyStmt->bindValue(':performed_by', $data['assigned_by']);
            $historyStmt->bindValue(':assigned_to', $data['assigned_to']);
            $historyStmt->bindValue(':notes', isset($data['notes']) ? $data['notes'] : null);
            $historyStmt->bindValue(':ip_address', $_SERVER['REMOTE_ADDR']);
            $historyStmt->execute();
            
            // Create notification for the assigned admin
            if (isset($data['send_notification']) && $data['send_notification']) {
                // Get member name
                $memberQuery = "SELECT CONCAT(first_name, ' ', last_name) as member_name FROM members WHERE id = :member_id";
                $memberStmt = $conn->prepare($memberQuery);
                $memberStmt->bindValue(':member_id', $data['member_id']);
                $memberStmt->execute();
                $memberName = $memberStmt->fetch(PDO::FETCH_ASSOC)['member_name'];
                
                // Create notification
                $this->notificationService->createNotification([
                    'type' => 'info',
                    'title' => 'New Member Assignment',
                    'message' => "You have been assigned to review the member: $memberName. Please review their information and take appropriate action.",
                    'target_audience' => 'specific',
                    'target_user_id' => $data['assigned_to'],
                    'user_type' => 'admin',
                    'created_by' => $data['assigned_by'],
                    'priority' => $data['priority'],
                    'related_entity_type' => 'member',
                    'related_entity_id' => $data['member_id']
                ]);
            }
            
            // Commit transaction
            $conn->commit();
            
            return [
                'success' => true,
                'assignment_id' => $assignmentId
            ];
            
        } catch (Exception $e) {
            // Rollback transaction on error
            if (isset($conn)) {
                $conn->rollBack();
            }
            
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Update assignment status
     *
     * @param array $data Update data
     * @return array Result with success status
     */
    public function updateStatus($data) {
        try {
            $conn = $this->db->getConnection();
            
            // Start transaction
            $conn->beginTransaction();
            
            $assignmentId = $data['assignment_id'];
            $status = $data['status'];
            $notes = isset($data['notes']) ? $data['notes'] : null;
            $userId = $data['user_id'];
            
            // Get assignment details first
            $getQuery = "SELECT member_id, assigned_to, assigned_by FROM admin_assignments WHERE id = :assignment_id";
            $getStmt = $conn->prepare($getQuery);
            $getStmt->bindValue(':assignment_id', $assignmentId);
            $getStmt->execute();
            
            if ($getStmt->rowCount() === 0) {
                throw new Exception("Assignment not found");
            }
            
            $assignment = $getStmt->fetch(PDO::FETCH_ASSOC);
            
            // Update assignment
            $query = "UPDATE admin_assignments 
                      SET status = :status, 
                          notes = CONCAT(IFNULL(notes, ''), '\n\n', :notes),
                          completed_at = :completed_at,
                          updated_at = NOW()
                      WHERE id = :assignment_id";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':status', $status);
            $stmt->bindValue(':notes', $notes);
            $stmt->bindValue(':completed_at', ($status === 'completed') ? date('Y-m-d H:i:s') : null);
            $stmt->bindValue(':assignment_id', $assignmentId);
            $stmt->execute();
            
            // If assignment is completed, clear the assigned_to field in members table
            if ($status === 'completed') {
                $updateMemberQuery = "UPDATE members 
                                     SET assigned_to = NULL,
                                         assignment_notes = CONCAT(IFNULL(assignment_notes, ''), '\n\n', :notes, '\n(Completed on ', NOW(), ')')
                                     WHERE id = :member_id";
                $updateMemberStmt = $conn->prepare($updateMemberQuery);
                $updateMemberStmt->bindValue(':notes', $notes);
                $updateMemberStmt->bindValue(':member_id', $assignment['member_id']);
                $updateMemberStmt->execute();
                
                // Add to member approval history
                $historyQuery = "INSERT INTO member_approval_history 
                                 (member_id, action, performed_by, notes, ip_address) 
                                 VALUES 
                                 (:member_id, 'updated', :performed_by, :notes, :ip_address)";
                $historyStmt = $conn->prepare($historyQuery);
                $historyStmt->bindValue(':member_id', $assignment['member_id']);
                $historyStmt->bindValue(':performed_by', $userId);
                $historyStmt->bindValue(':notes', "Assignment completed: $notes");
                $historyStmt->bindValue(':ip_address', $_SERVER['REMOTE_ADDR']);
                $historyStmt->execute();
            }
            
            // Create notification for the admin who assigned this task
            if ($status === 'completed' && $assignment['assigned_by'] != $userId) {
                // Get member name
                $memberQuery = "SELECT CONCAT(first_name, ' ', last_name) as member_name FROM members WHERE id = :member_id";
                $memberStmt = $conn->prepare($memberQuery);
                $memberStmt->bindValue(':member_id', $assignment['member_id']);
                $memberStmt->execute();
                $memberName = $memberStmt->fetch(PDO::FETCH_ASSOC)['member_name'];
                
                // Get admin name
                $adminQuery = "SELECT CONCAT(first_name, ' ', last_name) as admin_name FROM admins WHERE id = :admin_id";
                $adminStmt = $conn->prepare($adminQuery);
                $adminStmt->bindValue(':admin_id', $userId);
                $adminStmt->execute();
                $adminName = $adminStmt->fetch(PDO::FETCH_ASSOC)['admin_name'];
                
                // Create notification
                $this->notificationService->createNotification([
                    'type' => 'success',
                    'title' => 'Assignment Completed',
                    'message' => "$adminName has completed the review assignment for member: $memberName.",
                    'target_audience' => 'specific',
                    'target_user_id' => $assignment['assigned_by'],
                    'user_type' => 'admin',
                    'created_by' => $userId,
                    'priority' => 'normal',
                    'related_entity_type' => 'member',
                    'related_entity_id' => $assignment['member_id']
                ]);
            }
            
            // Commit transaction
            $conn->commit();
            
            return [
                'success' => true,
                'status' => $status
            ];
            
        } catch (Exception $e) {
            // Rollback transaction on error
            if (isset($conn)) {
                $conn->rollBack();
            }
            
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Get assignments for an admin
     *
     * @param int $adminId Admin ID
     * @param string $status Status filter (optional)
     * @param int $limit Maximum number of assignments to return
     * @return array Assignments
     */
    public function getAssignmentsForAdmin($adminId, $status = null, $limit = 10) {
        try {
            $conn = $this->db->getConnection();
            
            $whereClause = "WHERE aa.assigned_to = :admin_id";
            $params = [':admin_id' => $adminId];
            
            if ($status) {
                $whereClause .= " AND aa.status = :status";
                $params[':status'] = $status;
            }
            
            $query = "SELECT 
                        aa.*,
                        m.kso_id, 
                        CONCAT(m.first_name, ' ', m.last_name) as member_name,
                        CONCAT(a_by.first_name, ' ', a_by.last_name) as assigned_by_name
                      FROM admin_assignments aa
                      JOIN members m ON aa.member_id = m.id
                      JOIN admins a_by ON aa.assigned_by = a_by.id
                      $whereClause
                      ORDER BY 
                        CASE 
                          WHEN aa.status = 'overdue' THEN 1
                          WHEN aa.priority = 'urgent' THEN 2
                          WHEN aa.priority = 'high' THEN 3
                          WHEN aa.priority = 'normal' THEN 4
                          WHEN aa.priority = 'low' THEN 5
                          ELSE 6
                        END,
                        aa.created_at DESC
                      LIMIT :limit";
            
            $stmt = $conn->prepare($query);
            foreach ($params as $key => $value) {
                $stmt->bindValue($key, $value);
            }
            $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
            $stmt->execute();
            
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
            
        } catch (Exception $e) {
            error_log("Error getting assignments: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Get assignments for a member
     *
     * @param int $memberId Member ID
     * @return array Assignments
     */
    public function getAssignmentsForMember($memberId) {
        try {
            $conn = $this->db->getConnection();
            
            $query = "SELECT 
                        aa.*,
                        CONCAT(a_to.first_name, ' ', a_to.last_name) as assigned_to_name,
                        CONCAT(a_by.first_name, ' ', a_by.last_name) as assigned_by_name
                      FROM admin_assignments aa
                      JOIN admins a_to ON aa.assigned_to = a_to.id
                      JOIN admins a_by ON aa.assigned_by = a_by.id
                      WHERE aa.member_id = :member_id
                      ORDER BY aa.created_at DESC";
            
            $stmt = $conn->prepare($query);
            $stmt->bindValue(':member_id', $memberId);
            $stmt->execute();
            
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
            
        } catch (Exception $e) {
            error_log("Error getting member assignments: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Check for overdue assignments and update their status
     *
     * @return int Number of updated assignments
     */
    public function checkOverdueAssignments() {
        try {
            $conn = $this->db->getConnection();
            
            // Get assignments that are past due date and still active
            $query = "SELECT id, member_id, assigned_to, assigned_by 
                      FROM admin_assignments 
                      WHERE status = 'active' 
                      AND due_date IS NOT NULL 
                      AND due_date < NOW()";
            $stmt = $conn->query($query);
            
            $overdueAssignments = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            if (empty($overdueAssignments)) {
                return 0;
            }
            
            // Update assignments to overdue
            $updateQuery = "UPDATE admin_assignments 
                           SET status = 'overdue', 
                               updated_at = NOW() 
                           WHERE id IN (" . implode(',', array_column($overdueAssignments, 'id')) . ")";
            $conn->exec($updateQuery);
            
            // Create notifications for overdue assignments
            foreach ($overdueAssignments as $assignment) {
                // Get member name
                $memberQuery = "SELECT CONCAT(first_name, ' ', last_name) as member_name FROM members WHERE id = :member_id";
                $memberStmt = $conn->prepare($memberQuery);
                $memberStmt->bindValue(':member_id', $assignment['member_id']);
                $memberStmt->execute();
                $memberName = $memberStmt->fetch(PDO::FETCH_ASSOC)['member_name'];
                
                // Create notification for the assigned admin
                $this->notificationService->createNotification([
                    'type' => 'warning',
                    'title' => 'Assignment Overdue',
                    'message' => "Your assignment for member: $memberName is now overdue. Please complete it as soon as possible.",
                    'target_audience' => 'specific',
                    'target_user_id' => $assignment['assigned_to'],
                    'user_type' => 'admin',
                    'created_by' => 1, // System user ID
                    'priority' => 'high',
                    'related_entity_type' => 'member',
                    'related_entity_id' => $assignment['member_id']
                ]);
                
                // Create notification for the admin who assigned this task
                if ($assignment['assigned_by'] != $assignment['assigned_to']) {
                    $adminQuery = "SELECT CONCAT(first_name, ' ', last_name) as admin_name FROM admins WHERE id = :admin_id";
                    $adminStmt = $conn->prepare($adminQuery);
                    $adminStmt->bindValue(':admin_id', $assignment['assigned_to']);
                    $adminStmt->execute();
                    $adminName = $adminStmt->fetch(PDO::FETCH_ASSOC)['admin_name'];
                    
                    $this->notificationService->createNotification([
                        'type' => 'warning',
                        'title' => 'Assignment Overdue',
                        'message' => "The assignment for member: $memberName assigned to $adminName is now overdue.",
                        'target_audience' => 'specific',
                        'target_user_id' => $assignment['assigned_by'],
                        'user_type' => 'admin',
                        'created_by' => 1, // System user ID
                        'priority' => 'normal',
                        'related_entity_type' => 'member',
                        'related_entity_id' => $assignment['member_id']
                    ]);
                }
            }
            
            return count($overdueAssignments);
            
        } catch (Exception $e) {
            error_log("Error checking overdue assignments: " . $e->getMessage());
            return 0;
        }
    }

    /**
     * Auto-assign new members to admins based on workload
     *
     * @param int $memberId Member ID
     * @return array Result with success status and assignment ID
     */
    public function autoAssignMember($memberId) {
        try {
            $conn = $this->db->getConnection();
            
            // Check if auto-assignment is enabled
            $settingQuery = "SELECT setting_value FROM settings WHERE setting_key = 'member_auto_assignment'";
            $settingStmt = $conn->query($settingQuery);
            
            if ($settingStmt->rowCount() === 0 || $settingStmt->fetch(PDO::FETCH_ASSOC)['setting_value'] == '0') {
                return [
                    'success' => false,
                    'message' => 'Auto-assignment is disabled'
                ];
            }
            
            // Find the admin with the least active assignments
            $adminQuery = "SELECT 
                            a.id, 
                            COALESCE(COUNT(aa.id), 0) as assignment_count
                           FROM admins a
                           LEFT JOIN admin_assignments aa ON a.id = aa.assigned_to AND aa.status IN ('active', 'overdue')
                           WHERE a.status = 'active'
                           GROUP BY a.id
                           ORDER BY assignment_count ASC, a.id ASC
                           LIMIT 1";
            $adminStmt = $conn->query($adminQuery);
            
            if ($adminStmt->rowCount() === 0) {
                return [
                    'success' => false,
                    'message' => 'No active admins found'
                ];
            }
            
            $admin = $adminStmt->fetch(PDO::FETCH_ASSOC);
            $adminId = $admin['id'];
            
            // Create assignment
            return $this->assignMember([
                'member_id' => $memberId,
                'assigned_to' => $adminId,
                'assigned_by' => 1, // System user ID
                'assignment_type' => 'review',
                'priority' => 'normal',
                'send_notification' => true,
                'notes' => 'Auto-assigned by the system based on workload balancing.'
            ]);
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }
}
