package com.dne.ems.service.impl;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.dne.ems.dto.AttachmentDTO;
import com.dne.ems.dto.TaskDetailDTO;
import com.dne.ems.dto.TaskDetailDTO.SubmissionInfoDTO;
import com.dne.ems.dto.TaskHistoryDTO;
import com.dne.ems.dto.TaskSubmissionRequest;
import com.dne.ems.dto.TaskSummaryDTO;
import com.dne.ems.exception.InvalidOperationException;
import com.dne.ems.exception.ResourceNotFoundException;
import com.dne.ems.model.Attachment;
import com.dne.ems.model.Feedback;
import com.dne.ems.model.Task;
import com.dne.ems.model.TaskHistory;
import com.dne.ems.model.TaskSubmission;
import com.dne.ems.model.UserAccount;
import com.dne.ems.model.enums.SeverityLevel;
import com.dne.ems.model.enums.TaskStatus;
import com.dne.ems.repository.AttachmentRepository;
import com.dne.ems.repository.TaskHistoryRepository;
import com.dne.ems.repository.TaskRepository;
import com.dne.ems.repository.TaskSubmissionRepository;
import com.dne.ems.security.CustomUserDetails;
import com.dne.ems.service.FileStorageService;
import com.dne.ems.service.GridWorkerTaskService;
import com.dne.ems.service.OperationLogService;

import lombok.RequiredArgsConstructor;

/**
 * 网格员任务服务实现类，处理网格员的任务管理操作
 *
 * <p>实现了 {@link GridWorkerTaskService} 接口定义的所有方法，包括：
 * <ul>
 *   <li>获取分配的任务列表</li>
 *   <li>接受任务</li>
 *   <li>提交任务完成情况</li>
 *   <li>查看任务详情</li>
 * </ul>
 *
 * @author DNE开发团队
 * @version 1.0
 * @since 2024
 */
@Service
@RequiredArgsConstructor
public class GridWorkerTaskServiceImpl implements GridWorkerTaskService {

    private final TaskRepository taskRepository;
    private final TaskHistoryRepository taskHistoryRepository;
    private final TaskSubmissionRepository taskSubmissionRepository;
    // private final UserAccountRepository userAccountRepository;
    private final FileStorageService fileStorageService;
    private final AttachmentRepository attachmentRepository;
    private final OperationLogService operationLogService;

    @Value("${app.base.url}")
    private String appBaseUrl;

    /**
     * {@inheritDoc}
     *
     * <p>实现细节：
     * <ol>
     *   <li>验证分页排序参数，默认按创建时间降序</li>
     *   <li>构建动态查询条件</li>
     *   <li>查询并转换结果</li>
     * </ol>
     *
     * @param workerId 网格员ID
     * @param status 任务状态过滤条件(可选)
     * @param pageable 分页参数
     * @return 任务摘要分页列表
     */
    @Override
    public Page<TaskSummaryDTO> getAssignedTasks(Long workerId, TaskStatus status, Pageable pageable) {
        if (pageable.getSort().isUnsorted()) {
            pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by("createdAt").descending());
        }

        List<Task> allTasks = taskRepository.findAll();

        List<Task> filteredTasks = allTasks.stream()
            .filter(task -> task.getAssignee() != null && task.getAssignee().getId().equals(workerId))
            .filter(task -> status == null || task.getStatus() == status)
            .collect(Collectors.toList());

        // Manual sorting
        if (pageable.getSort().isSorted() && pageable.getSort().getOrderFor("createdAt") != null && pageable.getSort().getOrderFor("createdAt").isDescending()) {
             filteredTasks.sort((t1, t2) -> t2.getCreatedAt().compareTo(t1.getCreatedAt()));
        }

        // Manual pagination
        int start = (int) pageable.getOffset();
        int end = Math.min((start + pageable.getPageSize()), filteredTasks.size());
        
        List<Task> pageContent = (start > filteredTasks.size()) ? List.of() : filteredTasks.subList(start, end);

        Page<Task> taskPage = new PageImpl<>(pageContent, pageable, filteredTasks.size());
        return taskPage.map(this::convertToSummaryDto);
    }

    /**
     * {@inheritDoc}
     *
     * <p>实现细节：
     * <ol>
     *   <li>验证任务所有权</li>
     *   <li>检查任务状态是否可接受</li>
     *   <li>更新任务状态</li>
     *   <li>记录任务历史</li>
     * </ol>
     *
     * @param taskId 任务ID
     * @param workerId 网格员ID
     * @return 更新后的任务摘要
     * @throws InvalidOperationException 如果任务状态不允许接受
     */
    @Override
    public TaskSummaryDTO acceptTask(Long taskId, Long workerId) {
        Task task = validateTaskOwnership(taskId, workerId);
        if (task.getStatus() != TaskStatus.ASSIGNED) {
            throw new InvalidOperationException("Task cannot be accepted. Current status: " + task.getStatus());
        }
        TaskStatus oldStatus = task.getStatus();
        task.setStatus(TaskStatus.IN_PROGRESS);
        Task updatedTask = taskRepository.save(task);
        logTaskHistory(updatedTask, oldStatus, updatedTask.getStatus(), "Task accepted by worker.");
        
        operationLogService.recordOperation(
            com.dne.ems.model.enums.OperationType.UPDATE,
            "接受了任务 (ID: " + taskId + ")",
            taskId.toString(),
            "Task"
        );
        
        return convertToSummaryDto(updatedTask);
    }

    /**
     * {@inheritDoc}
     *
     * <p>实现细节：
     * <ol>
     *   <li>验证任务所有权</li>
     *   <li>检查任务状态是否可提交</li>
     *   <li>创建任务提交记录</li>
     *   <li>更新任务状态</li>
     *   <li>记录任务历史</li>
     * </ol>
     *
     * @param taskId 任务ID
     * @param workerId 网格员ID
     * @param request 包含提交说明的请求体
     * @return 更新后的任务摘要
     * @throws InvalidOperationException 如果任务状态不允许提交
     */
    @Override
    public TaskSummaryDTO submitTaskCompletion(Long taskId, Long workerId, TaskSubmissionRequest request) {
        return submitTaskCompletion(taskId, workerId, request, null);
    }

    @Override
    @Transactional
    public TaskSummaryDTO submitTaskCompletion(Long taskId, Long workerId, TaskSubmissionRequest request, List<MultipartFile> files) {
        Task task = validateTaskOwnership(taskId, workerId);
        if (task.getStatus() != TaskStatus.IN_PROGRESS && task.getStatus() != TaskStatus.ASSIGNED) {
            throw new InvalidOperationException("Task must be IN_PROGRESS or ASSIGNED to be submitted. Current status: " + task.getStatus());
        }

        // 1. 先更新并保存任务状态
        TaskStatus oldStatus = task.getStatus();
        task.setStatus(TaskStatus.SUBMITTED);
        Task updatedTask = taskRepository.save(task);

        // 2. 然后创建并保存提交记录
        TaskSubmission submission = new TaskSubmission(updatedTask, request.comments());
        taskSubmissionRepository.save(submission);

        // 3. 最后处理附件
        if (files != null && !files.isEmpty()) {
            for (MultipartFile file : files) {
                String storedFileName = fileStorageService.storeFile(file);
                Attachment attachment = Attachment.builder()
                        .fileName(file.getOriginalFilename())
                        .fileType(file.getContentType())
                        .fileSize(file.getSize())
                        .storedFileName(storedFileName)
                        .taskSubmission(submission)
                        .build();
                attachmentRepository.save(attachment);
            }
        }

        // 4. 记录历史
        logTaskHistory(updatedTask, oldStatus, updatedTask.getStatus(), "Worker submitted comments: " + request.comments());
        
        operationLogService.recordOperation(
            com.dne.ems.model.enums.OperationType.SUBMIT_TASK,
            "提交了任务 (ID: " + taskId + ") 的完成情况",
            taskId.toString(),
            "Task"
        );
        
        return convertToSummaryDto(updatedTask);
    }

    /**
     * {@inheritDoc}
     *
     * <p>实现细节：
     * <ol>
     *   <li>验证任务所有权</li>
     *   <li>转换任务详情DTO</li>
     * </ol>
     *
     * @param taskId 任务ID
     * @param workerId 网格员ID
     * @return 任务详情DTO
     */
    @Override
    public TaskDetailDTO getTaskDetails(Long taskId, Long workerId) {
        Task task = validateTaskOwnership(taskId, workerId);
        return convertToDetailDto(task);
    }
    
    /**
     * 验证任务所有权
     *
     * @param taskId 任务ID
     * @param workerId 网格员ID
     * @return 验证通过的任务实体
     * @throws ResourceNotFoundException 如果任务不存在
     * @throws AccessDeniedException 如果任务不属于当前网格员
     */
    private Task validateTaskOwnership(Long taskId, Long workerId) {
        Task task = taskRepository.findById(taskId).orElseThrow(() -> new ResourceNotFoundException("Task not found"));
        if (task.getAssignee() == null || !Objects.equals(task.getAssignee().getId(), workerId)) {
            throw new AccessDeniedException("This task is not assigned to you.");
        }
        return task;
    }

    /**
     * 记录任务历史
     *
     * @param task 任务实体
     * @param oldStatus 旧状态
     * @param newStatus 新状态
     * @param comments 备注信息
     */
    private void logTaskHistory(Task task, TaskStatus oldStatus, TaskStatus newStatus, String comments) {
        UserAccount currentUser = ((CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUserAccount();
        TaskHistory history = new TaskHistory(task, oldStatus, newStatus, currentUser, comments);
        taskHistoryRepository.save(history);
    }
    
    /**
     * 转换任务实体为摘要DTO
     *
     * @param task 任务实体
     * @return 任务摘要DTO
     */
    private TaskSummaryDTO convertToSummaryDto(Task task) {
        SeverityLevel severity = task.getFeedback() != null ? task.getFeedback().getSeverityLevel() : task.getSeverityLevel();
        String imageUrl = "";
        if (task.getFeedback() != null && task.getFeedback().getAttachments() != null && !task.getFeedback().getAttachments().isEmpty()) {
            imageUrl = appBaseUrl + "/api/files/view/" + task.getFeedback().getAttachments().get(0).getStoredFileName();
        }
        return new TaskSummaryDTO(
            task.getId(),
            task.getTitle(),
            task.getDescription(),
            task.getStatus(),
            task.getAssignee() != null ? task.getAssignee().getName() : null,
            task.getCreatedAt(),
            task.getTextAddress(),
            imageUrl,
            severity
        );
    }

    /**
     * 转换任务实体为详情DTO
     *
     * @param task 任务实体
     * @return 任务详情DTO
     */
    private TaskDetailDTO convertToDetailDto(Task task) {
        TaskDetailDTO.FeedbackDTO feedbackDto = null;
        if (task.getFeedback() != null) {
            Feedback feedback = task.getFeedback();
            List<String> imageUrls = feedback.getAttachments().stream()
                .map(att -> appBaseUrl + "/api/files/" + att.getStoredFileName())
                .collect(Collectors.toList());

            feedbackDto = new TaskDetailDTO.FeedbackDTO(
                feedback.getId(),
                feedback.getEventId(),
                feedback.getTitle(),
                feedback.getDescription(),
                feedback.getSeverityLevel(),
                feedback.getTextAddress(),
                feedback.getSubmitterId(),
                null, // Submitter name - can be fetched if needed
                feedback.getCreatedAt(),
                imageUrls
            );
        }

        TaskDetailDTO.AssigneeDTO assigneeDto = null;
        if (task.getAssignee() != null) {
            assigneeDto = new TaskDetailDTO.AssigneeDTO(task.getAssignee().getId(), task.getAssignee().getName(), task.getAssignee().getPhone());
        }

        List<TaskHistoryDTO> historyDtos = task.getHistory().stream()
            .map(this::convertToHistoryDto)
            .collect(Collectors.toList());

        // Fetch and build SubmissionInfoDTO
        TaskSubmission latestSubmission = taskSubmissionRepository.findFirstByTaskOrderBySubmittedAtDesc(task);
        SubmissionInfoDTO submissionInfoDto = null;
        if (latestSubmission != null) {
            List<Attachment> attachments = attachmentRepository.findByTaskSubmission(latestSubmission);
            List<AttachmentDTO> attachmentDtos = attachments.stream()
                .map(AttachmentDTO::fromEntity)
                .collect(Collectors.toList());
            submissionInfoDto = new SubmissionInfoDTO(latestSubmission.getNotes(), attachmentDtos);
        }

        return new TaskDetailDTO(
            task.getId(),
            feedbackDto,
            task.getTitle(),
            task.getDescription(),
            task.getSeverityLevel(),
            task.getPollutionType(),
            task.getTextAddress(),
            task.getGridX(),
            task.getGridY(),
            task.getStatus(),
            assigneeDto,
            task.getAssignedAt(),
            task.getCompletedAt(),
            historyDtos,
            submissionInfoDto
        );
    }

    /**
     * 转换任务历史实体为DTO
     *
     * @param history 任务历史实体
     * @return 任务历史DTO
     */
    private TaskHistoryDTO convertToHistoryDto(TaskHistory history) {
        UserAccount changedBy = history.getChangedBy();
        return new TaskHistoryDTO(
            history.getId(),
            history.getOldStatus(),
            history.getNewStatus(),
            history.getComments(),
            history.getChangedAt(),
            new TaskHistoryDTO.UserDTO(changedBy.getId(), changedBy.getName())
        );
    }
}