package com.lesingle.edu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lesingle.edu.common.enums.TaskStatus;
import com.lesingle.edu.common.enums.TaskCompletionStatus;
import com.lesingle.edu.common.enums.ErrorCode;
import com.lesingle.edu.common.exception.BusinessException;
import com.lesingle.edu.common.response.PageResult;
import com.lesingle.edu.dto.request.TaskCreateRequest;
import com.lesingle.edu.dto.request.TaskSubmitRequest;
import com.lesingle.edu.dto.request.TaskUpdateRequest;
import com.lesingle.edu.dto.response.TaskCompletionDetailResponse;
import com.lesingle.edu.dto.response.TaskFeedbackResponse;
import com.lesingle.edu.dto.response.TaskResponse;
import com.lesingle.edu.dto.response.TaskWithCompletionResponse;
import com.lesingle.edu.entity.*;
import com.lesingle.edu.mapper.CoursePackageMapper;
import com.lesingle.edu.mapper.ParentStudentMapper;
import com.lesingle.edu.mapper.TaskCompletionMapper;
import com.lesingle.edu.mapper.TaskMapper;
import com.lesingle.edu.mapper.TaskTargetMapper;
import com.lesingle.edu.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task>
    implements TaskService {

    private final TaskMapper taskMapper;
    private final TaskTargetMapper taskTargetMapper;
    private final TaskCompletionMapper taskCompletionMapper;
    private final CoursePackageMapper coursePackageMapper;
    private final ParentStudentMapper parentStudentMapper;
    private final StudentService studentService;
    private final ClassService classService;
    private final TaskFeedbackService taskFeedbackService;
    private final ObjectMapper objectMapper;

    @Override
    @Transactional
    public Task createTask(Long tenantId, Long creatorId, String creatorRole, TaskCreateRequest request) {
        Task task = new Task();
        task.setTenantId(tenantId);
        task.setTitle(request.getTitle());
        task.setDescription(request.getDescription());
        String taskType = request.getType() != null ? request.getType() : request.getTaskType();
        task.setType(taskType != null ? taskType : "homework");
        task.setRelatedBookName(request.getRelatedBookName()); // 添加关联绘本名称
        Long courseId = request.getCourseId() != null ? request.getCourseId() : request.getRelatedCourseId();
        task.setCourseId(courseId);
        task.setCreatorId(creatorId);
        task.setCreatorRole(creatorRole);
        task.setStartDate(request.getStartDate());
        LocalDate dueDate = request.getDueDate() != null ? request.getDueDate() : request.getEndDate();
        task.setDueDate(dueDate);
        task.setStatus(TaskStatus.PENDING.getCode());
        task.setAttachments(request.getAttachments());

        taskMapper.insert(task);
        log.info("任务创建成功：id={}, title={}", task.getId(), task.getTitle());

        // Create task targets
        if (request.getTargetIds() != null && !request.getTargetIds().isEmpty()) {
            for (Long targetId : request.getTargetIds()) {
                TaskTarget target = new TaskTarget();
                target.setTaskId(task.getId());
                target.setTargetType(request.getTargetType() != null ? request.getTargetType() : "class");
                target.setTargetId(targetId);
                taskTargetMapper.insert(target);
            }
        }

        return task;
    }

    @Override
    @Transactional
    public Task updateTask(Long id, TaskUpdateRequest request) {
        Task task = getTaskById(id);

        if (StringUtils.hasText(request.getTitle())) {
            task.setTitle(request.getTitle());
        }
        if (request.getDescription() != null) {
            task.setDescription(request.getDescription());
        }
        String taskType = request.getType() != null ? request.getType() : request.getTaskType();
        if (taskType != null) {
            task.setType(taskType);
        }
        if (request.getRelatedBookName() != null) {
            task.setRelatedBookName(request.getRelatedBookName());
        }
        Long courseId = request.getCourseId() != null ? request.getCourseId() : request.getRelatedCourseId();
        if (courseId != null) {
            task.setCourseId(courseId);
        }
        if (request.getStartDate() != null) {
            task.setStartDate(request.getStartDate());
        }
        if (request.getDueDate() != null) {
            task.setDueDate(request.getDueDate());
        }
        if (StringUtils.hasText(request.getStatus())) {
            task.setStatus(request.getStatus());
        }
        if (request.getAttachments() != null) {
            task.setAttachments(request.getAttachments());
        }

        taskMapper.updateById(task);

        // 更新任务目标
        if (request.getTargetIds() != null) {
            taskTargetMapper.delete(new LambdaQueryWrapper<TaskTarget>().eq(TaskTarget::getTaskId, id));
            if (!request.getTargetIds().isEmpty()) {
                String targetType = StringUtils.hasText(request.getTargetType()) ? request.getTargetType() : "CLASS";
                for (Long targetId : request.getTargetIds()) {
                    TaskTarget target = new TaskTarget();
                    target.setTaskId(id);
                    target.setTargetType(targetType);
                    target.setTargetId(targetId);
                    taskTargetMapper.insert(target);
                }
            }
        }

        log.info("任务更新成功：id={}", id);
        return task;
    }

    @Override
    public Task getTaskById(Long id) {
        Task task = taskMapper.selectById(id);
        if (task == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "任务不存在");
        }
        return task;
    }

    @Override
    public Task getTaskByIdWithTenantCheck(Long id, Long tenantId) {
        Task task = getTaskById(id);
        if (!task.getTenantId().equals(tenantId)) {
            throw new BusinessException(ErrorCode.FORBIDDEN, "无权访问该任务");
        }
        return task;
    }

    @Override
    public Task updateTaskWithTenantCheck(Long id, Long tenantId, TaskUpdateRequest request) {
        getTaskByIdWithTenantCheck(id, tenantId);
        return updateTask(id, request);
    }

    @Override
    public Page<Task> getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status) {
        return getTaskPage(tenantId, pageNum, pageSize, keyword, type, status, null, null, null);
    }

    @Override
    public Page<Task> getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status, Long creatorId) {
        return getTaskPage(tenantId, pageNum, pageSize, keyword, type, status, creatorId, null, null);
    }

    @Override
    public Page<Task> getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status, Long creatorId, String startDate, String endDate) {
        Page<Task> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Task::getTenantId, tenantId);

        if (creatorId != null) {
            wrapper.eq(Task::getCreatorId, creatorId);
        }
        if (StringUtils.hasText(keyword)) {
            wrapper.like(Task::getTitle, keyword);
        }
        if (StringUtils.hasText(type)) {
            wrapper.eq(Task::getType, type);
        }
        if (StringUtils.hasText(status)) {
            wrapper.eq(Task::getStatus, status);
        }

        // 任务时间筛选：与学校端 getSchoolTaskList 一致（任务区间与查询范围有交集）
        if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
            try {
                LocalDate rangeStart = LocalDate.parse(startDate);
                LocalDate rangeEnd = LocalDate.parse(endDate);
                wrapper.le(Task::getStartDate, rangeEnd);
                wrapper.and(w -> w.ge(Task::getDueDate, rangeStart).or().isNull(Task::getDueDate));
            } catch (Exception e) {
                log.warn("解析日期参数失败 startDate={}, endDate={}", startDate, endDate, e);
            }
        } else if (StringUtils.hasText(startDate)) {
            try {
                LocalDate rangeStart = LocalDate.parse(startDate);
                wrapper.ge(Task::getDueDate, rangeStart);
            } catch (Exception e) {
                log.warn("解析 startDate 参数失败: {}", startDate, e);
            }
        } else if (StringUtils.hasText(endDate)) {
            try {
                LocalDate rangeEnd = LocalDate.parse(endDate);
                wrapper.le(Task::getStartDate, rangeEnd);
            } catch (Exception e) {
                log.warn("解析 endDate 参数失败: {}", endDate, e);
            }
        }

        wrapper.orderByDesc(Task::getCreatedAt);

        return taskMapper.selectPage(page, wrapper);
    }

    @Override
    public Page<Task> getTasksByStudentId(Long studentId, Integer pageNum, Integer pageSize, String status) {
        Page<Task> page = new Page<>(pageNum, pageSize);

        // 从 task_target 获取任务：分配给该学生(target_type=STUDENT) 或 学生所在班级(target_type=CLASS)
        List<Long> taskIds = new ArrayList<>();

        // 1. 直接分配给学生的任务
        List<TaskTarget> studentTargets = taskTargetMapper.selectList(
                new LambdaQueryWrapper<TaskTarget>()
                        .in(TaskTarget::getTargetType, "STUDENT", "student")
                        .eq(TaskTarget::getTargetId, studentId)
        );
        taskIds.addAll(studentTargets.stream().map(TaskTarget::getTaskId).distinct().toList());

        // 2. 学生所在班级的任务
        Clazz primaryClass = classService.getPrimaryClassByStudentId(studentId);
        if (primaryClass != null) {
            List<TaskTarget> classTargets = taskTargetMapper.selectList(
                    new LambdaQueryWrapper<TaskTarget>()
                            .in(TaskTarget::getTargetType, "CLASS", "class")
                            .eq(TaskTarget::getTargetId, primaryClass.getId())
            );
            taskIds.addAll(classTargets.stream().map(TaskTarget::getTaskId).distinct().toList());
        }

        taskIds = taskIds.stream().distinct().toList();
        if (taskIds.isEmpty()) {
            return page;
        }

        LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Task::getId, taskIds);

        if (StringUtils.hasText(status)) {
            wrapper.eq(Task::getStatus, status);
        }
        wrapper.orderByDesc(Task::getCreatedAt);

        return taskMapper.selectPage(page, wrapper);
    }

    @Override
    public PageResult<TaskWithCompletionResponse> getTasksWithCompletionByStudentId(Long studentId, Integer pageNum, Integer pageSize, String status) {
        Page<Task> page = getTasksByStudentId(studentId, pageNum, pageSize, status);
        List<TaskWithCompletionResponse> responses = new ArrayList<>();

        for (Task task : page.getRecords()) {
            TaskCompletion completion = taskCompletionMapper.selectOne(
                    new LambdaQueryWrapper<TaskCompletion>()
                            .eq(TaskCompletion::getTaskId, task.getId())
                            .eq(TaskCompletion::getStudentId, studentId)
            );

            TaskWithCompletionResponse.TaskInfo.TaskInfoBuilder taskInfoBuilder = TaskWithCompletionResponse.TaskInfo.builder()
                    .id(task.getId())
                    .title(task.getTitle())
                    .description(task.getDescription())
                    .taskType(task.getType())
                    .startDate(task.getStartDate())
                    .endDate(task.getDueDate())
                    .relatedBookName(task.getRelatedBookName());

            if (task.getCourseId() != null) {
                CoursePackage course = coursePackageMapper.selectById(task.getCourseId());
                if (course != null) {
                    taskInfoBuilder.course(TaskWithCompletionResponse.CourseInfo.builder()
                            .id(course.getId())
                            .name(course.getName())
                            .build());
                }
            }

            TaskWithCompletionResponse.TaskWithCompletionResponseBuilder builder = TaskWithCompletionResponse.builder()
                    .id(task.getId())
                    .studentId(studentId)
                    .task(taskInfoBuilder.build());

            if (completion != null) {
                builder.status(completion.getStatus())
                        .submittedAt(completion.getSubmittedAt())
                        .reviewedAt(completion.getReviewedAt())
                        .photos(parsePhotos(completion.getPhotos()))
                        .videoUrl(completion.getVideoUrl())
                        .audioUrl(completion.getAudioUrl())
                        .content(completion.getContent());

                TaskFeedbackResponse feedback = taskFeedbackService.getFeedbackByCompletionId(completion.getId());
                builder.teacherFeedback(feedback);
            } else {
                builder.status(TaskStatus.PENDING.getCode());
            }

            responses.add(builder.build());
        }

        return PageResult.of(responses, page.getTotal(), page.getCurrent(), page.getSize());
    }

    @Override
    public PageResult<TaskWithCompletionResponse> getMyTasksForParent(Long parentId, Integer pageNum, Integer pageSize, String status) {
        List<Long> studentIds = studentService.getStudentsByParentId(parentId).stream()
                .map(Student::getId)
                .collect(Collectors.toList());
        if (studentIds.isEmpty()) {
            return PageResult.empty();
        }
        List<TaskWithCompletionResponse> all = new ArrayList<>();
        for (Long studentId : studentIds) {
            PageResult<TaskWithCompletionResponse> page = getTasksWithCompletionByStudentId(studentId, 1, 500, status);
            if (page.getList() != null) {
                all.addAll(page.getList());
            }
        }
        all.sort(Comparator.comparing(r -> r.getTask().getEndDate() != null ? r.getTask().getEndDate().atStartOfDay() : java.time.LocalDateTime.MIN, Comparator.reverseOrder()));
        long total = all.size();
        int from = (int) ((pageNum - 1) * pageSize);
        int to = Math.min(from + pageSize, all.size());
        List<TaskWithCompletionResponse> paged = from < all.size() ? all.subList(from, to) : Collections.emptyList();
        return PageResult.of(paged, total, (long) pageNum, (long) pageSize);
    }

    @Override
    @Transactional
    public void deleteTask(Long id) {
        getTaskById(id);
        taskMapper.deleteById(id);
        log.info("任务删除成功：id={}", id);
    }

    @Override
    @Transactional
    public void deleteTaskWithTenantCheck(Long id, Long tenantId) {
        getTaskByIdWithTenantCheck(id, tenantId);
        deleteTask(id);
    }

    @Override
    @Transactional
    public void completeTask(Long taskId, Long studentId, String content, String attachments) {
        TaskCompletion completion = taskCompletionMapper.selectOne(
                new LambdaQueryWrapper<TaskCompletion>()
                        .eq(TaskCompletion::getTaskId, taskId)
                        .eq(TaskCompletion::getStudentId, studentId)
        );

        if (completion == null) {
            completion = new TaskCompletion();
            completion.setTaskId(taskId);
            completion.setStudentId(studentId);
            completion.setStatus(TaskStatus.COMPLETED.getCode());
            completion.setCompletedAt(LocalDateTime.now());
            completion.setContent(content);
            completion.setAttachments(attachments);
            taskCompletionMapper.insert(completion);
            log.info("任务完成：taskId={}, studentId={}", taskId, studentId);
        } else {
            completion.setStatus(TaskStatus.COMPLETED.getCode());
            completion.setCompletedAt(LocalDateTime.now());
            completion.setContent(content);
            completion.setAttachments(attachments);
            taskCompletionMapper.updateById(completion);
            log.info("任务更新完成：taskId={}, studentId={}", taskId, studentId);
        }
    }

    @Override
    public List<Task> getTasksByClassId(Long classId) {
        List<TaskTarget> targets = taskTargetMapper.selectList(
                new LambdaQueryWrapper<TaskTarget>()
                        .eq(TaskTarget::getTargetType, "class")
                        .eq(TaskTarget::getTargetId, classId)
        );

        if (targets.isEmpty()) {
            return new ArrayList<>();
        }

        List<Long> taskIds = targets.stream()
                .map(TaskTarget::getTaskId)
                .toList();

        return taskMapper.selectList(
                new LambdaQueryWrapper<Task>()
                        .in(Task::getId, taskIds)
                        .orderByDesc(Task::getCreatedAt)
        );
    }

    // =============== 完成情况与评价相关方法实现 ===============

    @Override
    public PageResult<TaskCompletionDetailResponse> getTaskCompletions(Long taskId, Long tenantId, Integer pageNum, Integer pageSize, String status) {
        // 验证任务存在且属于该租户
        Task task = getTaskByIdWithTenantCheck(taskId, tenantId);

        // status=PENDING 待提交：返回参与任务且与家长关联、尚未提交的学生（无 task_completion 记录）
        if (TaskStatus.PENDING.getCode().equalsIgnoreCase(status)) {
            return getPendingCompletions(taskId, tenantId, pageNum, pageSize, task);
        }

        Page<TaskCompletion> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<TaskCompletion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TaskCompletion::getTaskId, taskId);

        if (StringUtils.hasText(status)) {
            wrapper.eq(TaskCompletion::getStatus, status);
        }
        wrapper.orderByDesc(TaskCompletion::getCreatedAt);

        Page<TaskCompletion> completionPage = taskCompletionMapper.selectPage(page, wrapper);

        List<TaskCompletionDetailResponse> responses = completionPage.getRecords().stream()
                .map(this::buildCompletionDetailResponse)
                .toList();

        return PageResult.of(responses, completionPage.getTotal(), completionPage.getCurrent(), completionPage.getSize());
    }

    /**
     * 获取待提交学生列表：参与任务（班级或指定学生）且与家长关联、尚未提交的学生
     */
    private PageResult<TaskCompletionDetailResponse> getPendingCompletions(Long taskId, Long tenantId, Integer pageNum, Integer pageSize, Task task) {
        List<Long> targetStudentIds = getTargetStudentIdsForTask(taskId);
        if (targetStudentIds.isEmpty()) {
            return PageResult.empty();
        }

        // 仅保留与家长关联的学生（parent_student 有记录）
        List<Long> studentIdsWithParent = parentStudentMapper.selectList(
                new LambdaQueryWrapper<ParentStudent>()
                        .in(ParentStudent::getStudentId, targetStudentIds)
        ).stream().map(ParentStudent::getStudentId).distinct().toList();

        if (studentIdsWithParent.isEmpty()) {
            return PageResult.empty();
        }

        // 排除已提交或已评价的学生（已有 task_completion 且 status 非 PENDING）
        List<TaskCompletion> existing = taskCompletionMapper.selectList(
                new LambdaQueryWrapper<TaskCompletion>()
                        .eq(TaskCompletion::getTaskId, taskId)
                        .in(TaskCompletion::getStudentId, studentIdsWithParent)
                        .in(TaskCompletion::getStatus, "SUBMITTED", "REVIEWED", "submitted", "reviewed")
        );
        List<Long> submittedStudentIds = existing.stream().map(TaskCompletion::getStudentId).distinct().toList();
        List<Long> pendingStudentIds = studentIdsWithParent.stream()
                .filter(id -> !submittedStudentIds.contains(id))
                .toList();

        // 分页
        int from = (pageNum - 1) * pageSize;
        int to = Math.min(from + pageSize, pendingStudentIds.size());
        List<Long> pagedIds = from < pendingStudentIds.size() ? pendingStudentIds.subList(from, to) : List.of();

        List<TaskCompletionDetailResponse> responses = pagedIds.stream()
                .map(studentId -> buildPendingCompletionResponse(taskId, task.getTitle(), studentId))
                .toList();

        return PageResult.of(responses, (long) pendingStudentIds.size(), (long) pageNum, (long) pageSize);
    }

    /**
     * 获取任务目标学生 ID 列表（班级学生或指定学生）
     */
    private List<Long> getTargetStudentIdsForTask(Long taskId) {
        List<TaskTarget> targets = taskTargetMapper.selectList(
                new LambdaQueryWrapper<TaskTarget>().eq(TaskTarget::getTaskId, taskId)
        );
        if (targets.isEmpty()) {
            return List.of();
        }

        List<Long> studentIds = new ArrayList<>();
        for (TaskTarget t : targets) {
            String tt = t.getTargetType() != null ? t.getTargetType().toUpperCase() : "";
            if ("CLASS".equals(tt) || "class".equals(t.getTargetType())) {
                studentIds.addAll(studentService.getStudentListByClassId(t.getTargetId()).stream()
                        .map(Student::getId).toList());
            } else if ("STUDENT".equals(tt) || "student".equals(t.getTargetType())) {
                studentIds.add(t.getTargetId());
            }
        }
        return studentIds.stream().distinct().toList();
    }

    /**
     * 构建待提交的完成详情（无 task_completion 记录）
     */
    private TaskCompletionDetailResponse buildPendingCompletionResponse(Long taskId, String taskTitle, Long studentId) {
        Student student = studentService.getById(studentId);
        if (student == null) {
            return null;
        }
        TaskCompletionDetailResponse.StudentInfo studentInfo = TaskCompletionDetailResponse.StudentInfo.builder()
                .id(student.getId())
                .name(student.getName())
                .avatar(student.getAvatarUrl())
                .gender(student.getGender())
                .build();
        Clazz clazz = classService.getPrimaryClassByStudentId(student.getId());
        if (clazz != null) {
            studentInfo.setClassInfo(TaskCompletionDetailResponse.ClassInfo.builder()
                    .id(clazz.getId())
                    .name(clazz.getName())
                    .grade(clazz.getGrade())
                    .build());
        }
        return TaskCompletionDetailResponse.builder()
                .id(null)
                .taskId(taskId)
                .taskTitle(taskTitle)
                .student(studentInfo)
                .status(TaskStatus.PENDING.getCode())
                .statusText("待提交")
                .build();
    }

    @Override
    public TaskCompletionDetailResponse getCompletionDetail(Long completionId, Long tenantId) {
        TaskCompletion completion = taskCompletionMapper.selectById(completionId);
        if (completion == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "完成记录不存在");
        }

        // 验证任务属于该租户
        getTaskByIdWithTenantCheck(completion.getTaskId(), tenantId);

        return buildCompletionDetailResponse(completion);
    }

    /**
     * 构建完成详情响应
     */
    private TaskCompletionDetailResponse buildCompletionDetailResponse(TaskCompletion completion) {
        TaskCompletionDetailResponse.TaskCompletionDetailResponseBuilder builder = TaskCompletionDetailResponse.builder()
                .id(completion.getId())
                .taskId(completion.getTaskId())
                .status(completion.getStatus())
                .statusText(getStatusText(completion.getStatus()))
                .photos(parsePhotos(completion.getPhotos()))
                .videoUrl(completion.getVideoUrl())
                .audioUrl(completion.getAudioUrl())
                .content(completion.getContent())
                .submittedAt(completion.getSubmittedAt())
                .reviewedAt(completion.getReviewedAt());

        // 获取任务标题
        Task task = taskMapper.selectById(completion.getTaskId());
        if (task != null) {
            builder.taskTitle(task.getTitle());
        }

        // 获取学生信息
        if (completion.getStudentId() != null) {
            Student student = studentService.getById(completion.getStudentId());
            if (student != null) {
                TaskCompletionDetailResponse.StudentInfo studentInfo = TaskCompletionDetailResponse.StudentInfo.builder()
                        .id(student.getId())
                        .name(student.getName())
                        .avatar(student.getAvatarUrl())
                        .gender(student.getGender())
                        .build();

                // 获取班级信息
                Clazz clazz = classService.getPrimaryClassByStudentId(student.getId());
                if (clazz != null) {
                    TaskCompletionDetailResponse.ClassInfo classInfo = TaskCompletionDetailResponse.ClassInfo.builder()
                            .id(clazz.getId())
                            .name(clazz.getName())
                            .grade(clazz.getGrade())
                            .build();
                    studentInfo.setClassInfo(classInfo);
                }

                builder.student(studentInfo);
            }
        }

        // 获取评价信息
        TaskFeedbackResponse feedback = taskFeedbackService.getFeedbackByCompletionId(completion.getId());
        builder.feedback(feedback);

        return builder.build();
    }

    /**
     * 解析照片 JSON 数组
     */
    private List<String> parsePhotos(String photosJson) {
        if (!StringUtils.hasText(photosJson)) {
            return Collections.emptyList();
        }
        try {
            return objectMapper.readValue(photosJson, new TypeReference<List<String>>() {});
        } catch (Exception e) {
            log.warn("解析照片JSON失败: {}", e.getMessage());
            return Collections.emptyList();
        }
    }

    /**
     * 获取状态文本
     */
    private String getStatusText(String status) {
        if (status == null) {
            return "";
        }
        TaskCompletionStatus completionStatus = TaskCompletionStatus.fromCode(status);
        return completionStatus.getDescription();
    }

    @Override
    @Transactional
    public TaskCompletionDetailResponse submitTaskCompletion(Long taskId, TaskSubmitRequest request, Long tenantId) {
        log.info("提交任务完成：taskId={}, studentId={}", taskId, request.getStudentId());

        // 验证任务存在且属于该租户
        Task task = getTaskByIdWithTenantCheck(taskId, tenantId);

        // 验证学生ID
        if (request.getStudentId() == null) {
            throw new BusinessException(ErrorCode.INVALID_PARAMETER, "学生ID不能为空");
        }

        // 查找或创建完成记录
        TaskCompletion completion = taskCompletionMapper.selectOne(
                new LambdaQueryWrapper<TaskCompletion>()
                        .eq(TaskCompletion::getTaskId, taskId)
                        .eq(TaskCompletion::getStudentId, request.getStudentId())
        );

        LocalDateTime now = LocalDateTime.now();

        if (completion == null) {
            // 创建新记录
            completion = new TaskCompletion();
            completion.setTaskId(taskId);
            completion.setStudentId(request.getStudentId());
            completion.setStatus("SUBMITTED");
            completion.setPhotos(serializePhotos(request.getPhotos()));
            completion.setVideoUrl(request.getVideoUrl());
            completion.setAudioUrl(request.getAudioUrl());
            completion.setContent(request.getContent());
            completion.setSubmittedAt(now);
            completion.setCreatedAt(now);
            completion.setUpdatedAt(now);
            taskCompletionMapper.insert(completion);
            log.info("创建完成记录成功：completionId={}", completion.getId());
        } else {
            // 更新记录
            completion.setStatus("SUBMITTED");
            completion.setPhotos(serializePhotos(request.getPhotos()));
            completion.setVideoUrl(request.getVideoUrl());
            completion.setAudioUrl(request.getAudioUrl());
            completion.setContent(request.getContent());
            completion.setSubmittedAt(now);
            completion.setUpdatedAt(now);
            taskCompletionMapper.updateById(completion);
            log.info("更新完成记录成功：completionId={}", completion.getId());
        }

        return buildCompletionDetailResponse(completion);
    }

    /**
     * 序列化照片列表为 JSON
     */
    private String serializePhotos(List<String> photos) {
        if (photos == null || photos.isEmpty()) {
            return null;
        }
        try {
            return objectMapper.writeValueAsString(photos);
        } catch (Exception e) {
            log.warn("序列化照片JSON失败: {}", e.getMessage());
            return null;
        }
    }

    // =============== 学校端只读方法实现 ===============

    @Override
    public PageResult<TaskResponse> getSchoolTaskList(Long tenantId, Integer pageNum, Integer pageSize,
            String keyword, String type, String status,
            List<Long> classIds, List<Long> teacherIds,
            String dateType, String startDate, String endDate,
            String completionRate, String sortBy, String sortOrder) {

        log.info("获取学校端任务列表：tenantId={}", tenantId);

        Page<Task> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();

        // 租户过滤
        wrapper.eq(Task::getTenantId, tenantId);

        // 关键字搜索
        if (StringUtils.hasText(keyword)) {
            wrapper.like(Task::getTitle, keyword);
        }

        // 类型筛选
        if (StringUtils.hasText(type)) {
            wrapper.eq(Task::getType, type);
        }

        // 状态筛选
        if (StringUtils.hasText(status)) {
            wrapper.eq(Task::getStatus, status);
        }

        // 时间筛选：任务的 startDate~dueDate 与查询范围有交集的纳入结果
        // 交集条件：task.startDate <= endDate AND task.dueDate >= startDate
        if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
            try {
                LocalDate rangeStart = LocalDate.parse(startDate);
                LocalDate rangeEnd = LocalDate.parse(endDate);
                // 任务开始日期 <= 查询结束日期（任务不能完全在查询范围之后）
                wrapper.le(Task::getStartDate, rangeEnd);
                // 任务截止日期 >= 查询开始日期（任务不能完全在查询范围之前）
                wrapper.and(w -> w.ge(Task::getDueDate, rangeStart).or().isNull(Task::getDueDate));
            } catch (Exception e) {
                log.warn("解析日期参数失败 startDate={}, endDate={}", startDate, endDate, e);
            }
        } else if (StringUtils.hasText(startDate)) {
            try {
                LocalDate rangeStart = LocalDate.parse(startDate);
                wrapper.ge(Task::getDueDate, rangeStart);
            } catch (Exception e) {
                log.warn("解析 startDate 参数失败: {}", startDate, e);
            }
        } else if (StringUtils.hasText(endDate)) {
            try {
                LocalDate rangeEnd = LocalDate.parse(endDate);
                wrapper.le(Task::getStartDate, rangeEnd);
            } catch (Exception e) {
                log.warn("解析 endDate 参数失败: {}", endDate, e);
            }
        }

        // TODO: classIds、teacherIds、completionRate 筛选待实现

        // 排序
        boolean asc = "asc".equalsIgnoreCase(sortOrder);
        if ("startDate".equals(sortBy)) {
            wrapper.orderBy(true, asc, Task::getStartDate);
        } else if ("endDate".equals(sortBy) || "dueDate".equals(sortBy)) {
            wrapper.orderBy(true, asc, Task::getDueDate);
        } else {
            wrapper.orderBy(true, asc, Task::getCreatedAt);
        }

        Page<Task> taskPage = taskMapper.selectPage(page, wrapper);

        // 转换为响应对象
        // TODO: 使用 TaskMapper 转换
        List<TaskResponse> responses = taskPage.getRecords().stream()
                .map(task -> {
                    TaskResponse r = TaskResponse.builder()
                            .id(task.getId())
                            .tenantId(task.getTenantId())
                            .title(task.getTitle())
                            .description(task.getDescription())
                            .type(task.getType())
                            .relatedBookName(task.getRelatedBookName())
                            .courseId(task.getCourseId())
                            .creatorId(task.getCreatorId())
                            .creatorRole(task.getCreatorRole())
                            .startDate(task.getStartDate())
                            .dueDate(task.getDueDate())
                            .status(task.getStatus())
                            .attachments(task.getAttachments())
                            .createdAt(task.getCreatedAt())
                            .updatedAt(task.getUpdatedAt())
                            .build();
                    enrichTaskResponseWithStats(r, task.getId());
                    return r;
                })
                .toList();

        return PageResult.of(responses, taskPage.getTotal(), taskPage.getCurrent(), taskPage.getSize());
    }

    @Override
    public TaskResponse getTaskDetailForSchool(Long taskId, Long tenantId) {
        return buildTaskDetailResponse(taskId, tenantId);
    }

    /**
     * 获取任务详情（含目标类型、目标列表），用于编辑回显
     */
    public TaskResponse getTaskDetailWithTargets(Long taskId, Long tenantId) {
        return buildTaskDetailResponse(taskId, tenantId);
    }

    private TaskResponse buildTaskDetailResponse(Long taskId, Long tenantId) {
        Task task = getTaskByIdWithTenantCheck(taskId, tenantId);
        List<TaskTarget> targets = taskTargetMapper.selectList(
                new LambdaQueryWrapper<TaskTarget>().eq(TaskTarget::getTaskId, taskId));
        String targetType = targets.isEmpty() ? null : targets.get(0).getTargetType();
        List<Long> targetIds = targets.stream().map(TaskTarget::getTargetId).toList();

        TaskResponse response = TaskResponse.builder()
                .id(task.getId())
                .tenantId(task.getTenantId())
                .title(task.getTitle())
                .description(task.getDescription())
                .type(task.getType())
                .relatedBookName(task.getRelatedBookName())
                .courseId(task.getCourseId())
                .creatorId(task.getCreatorId())
                .creatorRole(task.getCreatorRole())
                .startDate(task.getStartDate())
                .dueDate(task.getDueDate())
                .status(task.getStatus())
                .attachments(task.getAttachments())
                .targetType(targetType)
                .targetIds(targetIds)
                .createdAt(task.getCreatedAt())
                .updatedAt(task.getUpdatedAt())
                .build();
        enrichTaskResponseWithStats(response, taskId);
        return response;
    }

    @Override
    public void enrichTaskResponseWithStats(TaskResponse response, Long taskId) {
        // targetCount: 任务分配的目标人数（班级学生数或直接指定学生数）
        int targetCount = 0;
        List<TaskTarget> targets = taskTargetMapper.selectList(
                new LambdaQueryWrapper<TaskTarget>().eq(TaskTarget::getTaskId, taskId));
        for (TaskTarget t : targets) {
            String tt = t.getTargetType() != null ? t.getTargetType().toUpperCase() : "";
            if ("CLASS".equals(tt)) {
                List<Student> students = studentService.getStudentListByClassId(t.getTargetId());
                targetCount += students != null ? students.size() : 0;
            } else if ("STUDENT".equals(tt)) {
                targetCount += 1;
            }
        }
        response.setTargetCount(targetCount);

        // completionCount: 已提交或已评价的人数
        long completionCount = taskCompletionMapper.selectCount(
                new LambdaQueryWrapper<TaskCompletion>()
                        .eq(TaskCompletion::getTaskId, taskId)
                        .in(TaskCompletion::getStatus, "SUBMITTED", "REVIEWED"));
        response.setCompletionCount((int) completionCount);
    }

}
