package com.dne.ems.service.impl;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dne.ems.model.Assignment;
import com.dne.ems.model.Feedback;
import com.dne.ems.model.Task;
import com.dne.ems.model.UserAccount;
import com.dne.ems.model.enums.AssignmentStatus;
import com.dne.ems.model.enums.FeedbackStatus;
import com.dne.ems.model.enums.Role;
import com.dne.ems.model.enums.TaskStatus;
import com.dne.ems.repository.AssignmentRepository;
import com.dne.ems.repository.FeedbackRepository;
import com.dne.ems.repository.TaskRepository;
import com.dne.ems.repository.UserAccountRepository;
import com.dne.ems.service.OperationLogService;
import com.dne.ems.service.TaskAssignmentService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 任务分配服务实现类
 * 
 * <p>该服务负责处理环境问题反馈的任务分配流程，
 * 包括获取待分配的反馈列表、查询可用的网格员，
 * 以及将反馈分配给网格员形成具体任务。</p>
 *
 * @version 1.0
 * @since 2025-06
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class TaskAssignmentServiceImpl implements TaskAssignmentService {

    private final FeedbackRepository feedbackRepository;
    private final UserAccountRepository userAccountRepository;
    private final AssignmentRepository assignmentRepository;
    private final TaskRepository taskRepository;
    private final OperationLogService operationLogService;

    /**
     * 获取所有未分配的反馈
     * 
     * <p>查询状态为PENDING_ASSIGNMENT的所有反馈记录，这些反馈已通过主管审核，
     * 等待分配给网格员处理。</p>
     *
     * @return 待分配的反馈列表
     */
    @Override
    public List<Feedback> getUnassignedFeedback() {
        // Unassigned feedback are those that have been approved and are awaiting assignment.
        return feedbackRepository.findByStatus(FeedbackStatus.PENDING_ASSIGNMENT);
    }

    /**
     * 获取所有可用的网格员
     * 
     * <p>查询系统中所有角色为GRID_WORKER的用户账号，作为任务分配的候选人。</p>
     *
     * @return 可用网格员列表
     * @throws RuntimeException 如果数据库查询过程中发生异常
     */
    @Override
    public List<UserAccount> getAvailableGridWorkers() {
        log.info("正在查询角色为 GRID_WORKER 的用户");
        try {
            List<UserAccount> workers = userAccountRepository.findByRole(Role.GRID_WORKER);
            log.info("数据库查询成功，返回 {} 名网格员", workers.size());
            return workers;
        } catch (Exception e) {
            log.error("从数据库查询网格员时发生异常", e);
            throw e; // 重新抛出异常，由Controller层处理
        }
    }

    /**
     * 分配任务给网格员
     * 
     * <p>将指定的反馈分配给指定的网格员处理，创建新的任务和分配记录，
     * 并更新反馈状态为已分配。整个过程在一个事务中完成，确保数据一致性。</p>
     *
     * @param feedbackId 反馈ID
     * @param assigneeId 被分配的网格员ID
     * @param assignerId 执行分配操作的管理员ID
     * @return 新创建的分配记录
     * @throws IllegalArgumentException 如果找不到指定ID的反馈、网格员或管理员
     * @throws IllegalStateException 如果反馈状态不允许分配
     */
    @Override
    @Transactional
    public Assignment assignTask(Long feedbackId, Long assigneeId, Long assignerId) {
        log.info("开始分配任务：feedbackId={}, assigneeId={}, assignerId={}", feedbackId, assigneeId, assignerId);

        // 1. 验证反馈是否存在且状态可分配
        Feedback feedback = feedbackRepository.findById(feedbackId)
                .orElseThrow(() -> {
                    log.error("分配任务失败：找不到ID为 {} 的反馈", feedbackId);
                    return new IllegalArgumentException("Feedback not found with ID: " + feedbackId);
                });

        if (feedback.getStatus() != FeedbackStatus.CONFIRMED && feedback.getStatus() != FeedbackStatus.PENDING_ASSIGNMENT) {
            log.error("分配任务失败：反馈ID {} 的状态为 {}，无法分配", feedbackId, feedback.getStatus());
            throw new IllegalStateException("Feedback with ID " + feedbackId + " is not in a CONFIRMED or PENDING_ASSIGNMENT state and cannot be assigned.");
        }

        // 2. 验证分配对象是否为有效的网格员
        UserAccount assignee = userAccountRepository.findById(assigneeId)
                .orElseThrow(() -> {
                    log.error("分配任务失败：找不到ID为 {} 的用户", assigneeId);
                    return new IllegalArgumentException("Assignee user not found with ID: " + assigneeId);
                });

        if (assignee.getRole() != Role.GRID_WORKER) {
            log.error("分配任务失败：用户ID {} 的角色为 {}，不是网格员", assigneeId, assignee.getRole());
            throw new IllegalArgumentException("User with ID " + assigneeId + " is not a grid worker.");
        }
        
        // 3. 验证分派人是否存在
        UserAccount assigner = userAccountRepository.findById(assignerId)
                .orElseThrow(() -> {
                    log.error("分配任务失败：找不到ID为 {} 的分派人", assignerId);
                    return new IllegalArgumentException("Assigner user not found with ID: " + assignerId);
                });

        // 4. 从反馈创建任务
        Task newTask = new Task();
        newTask.setFeedback(feedback);
        newTask.setAssignee(assignee);
        newTask.setCreatedBy(assigner);
        newTask.setStatus(TaskStatus.ASSIGNED);
        newTask.setAssignedAt(java.time.LocalDateTime.now());
        newTask.setTitle(feedback.getTitle());
        newTask.setDescription(feedback.getDescription());
        newTask.setPollutionType(feedback.getPollutionType());
        newTask.setSeverityLevel(feedback.getSeverityLevel());
        newTask.setLatitude(feedback.getLatitude());
        newTask.setLongitude(feedback.getLongitude());
        newTask.setTextAddress(feedback.getTextAddress());
        newTask.setGridX(feedback.getGridX());
        newTask.setGridY(feedback.getGridY());

        Task savedTask = taskRepository.save(newTask);
        log.info("新任务已创建并保存，ID：{}", savedTask.getId());

        // 5. 创建并保存新的分配记录
        Assignment newAssignment = new Assignment();
        newAssignment.setTask(savedTask);
        newAssignment.setAssigner(assigner);
        newAssignment.setStatus(AssignmentStatus.PENDING);
        Assignment savedAssignment = assignmentRepository.save(newAssignment);
        log.info("新分配记录已创建并保存，ID：{}", savedAssignment.getId());

        // 6. 更新反馈状态为"已分配"
        feedback.setStatus(FeedbackStatus.ASSIGNED);
        feedbackRepository.save(feedback);
        log.info("反馈ID {} 的状态已更新为 ASSIGNED", feedback.getId());

        // 记录操作日志
        operationLogService.recordOperation(
            com.dne.ems.model.enums.OperationType.ASSIGN_TASK,
            "任务(ID: " + savedTask.getId() + ") 已分配给网格员 " + assignee.getName() + " (ID: " + assignee.getId() + ")",
            savedTask.getId().toString(),
            "Task"
        );

        return savedAssignment;
    }
}