package org.dromara.system.service.impl;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import lombok.SneakyThrows;
import org.apache.poi.util.StringUtil;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.bo.FormalTeacherClassBo;
import org.dromara.system.domain.list.CourseTableList;
import org.dromara.system.domain.vo.CourseChangeVo;
import org.dromara.system.domain.vo.CourseTableTimeVo;
import org.dromara.system.domain.vo.FormalTeacherClassVo;
import org.dromara.system.mapper.CourseChangeMapper;
import org.dromara.system.mapper.CourseTableTimeMapper;
import org.dromara.system.service.IFormalTeacherClassService;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.CourseTableBo;
import org.dromara.system.domain.vo.CourseTableVo;
import org.dromara.system.domain.CourseTable;
import org.dromara.system.mapper.CourseTableMapper;
import org.dromara.system.service.ICourseTableService;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 课程Service业务层处理
 *
 * @author Lion Li
 * @date 2023-08-16
 */
@RequiredArgsConstructor
@Service
public class CourseTableServiceImpl implements ICourseTableService {

    private final CourseTableMapper baseMapper;

    private final CourseChangeMapper courseChangeMapper;

    private final CourseTableTimeMapper courseTableTimeMapper;

    private final IFormalTeacherClassService formalTeacherClassService;

    /**
     * 查询课程
     */
    @Override
    public CourseTableVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询课程列表
     */
    @SneakyThrows
    @Override
    public TableDataInfo<List<CourseTableVo>> queryPageList(CourseTableBo bo, PageQuery pageQuery) {
        if (StringUtils.isEmpty(bo.getClassId()) || StringUtils.isEmpty(bo.getSchoolId())) {
            return TableDataInfo.build(new ArrayList<>());
        }
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(bo);
        Page<CourseTableVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<CourseTableVo> courseTableList = result.getRecords();

        Map<String, List<CourseTableVo>> groupedByType = courseTableList.stream().collect(Collectors.groupingBy(CourseTableVo::getWeek));

        List<List<CourseTableVo>> groupedList = new ArrayList<>(groupedByType.values());

        //获取本周一和本周五的时间
        String fist = DateUtils.getTimeIntervalOne(new Date());
        String five = DateUtils.getTimeIntervalFive(fist);
        List<CourseChangeVo> courseChangeList = courseChangeMapper.selectCourseChangeListByEdit(bo.getClassId(), fist, five);
        if (courseChangeList != null && courseChangeList.size() > 0) {
            for (List<CourseTableVo> courseTableVos : groupedList) {
                //将修改后的课程放入当前周课表
                changeCourseTable(courseTableVos, courseChangeList, fist, five);
            }

            //如果当前角色是老师，获取老师的课程
            LoginUser user = LoginHelper.getLoginUser();
            Map<String, Object> params = bo.getParams();
            String ro = "";
            if (params != null && params.size() > 0) {
                ro = (String) params.get("role");
            }
            if (StringUtils.isNotEmpty(ro) && "teacher".equals(ro)) {
                //查询老师当前班级所带的课
                FormalTeacherClassBo ftbo = new FormalTeacherClassBo();
                ftbo.setClassId(Long.valueOf(bo.getClassId()));
                ftbo.setTeacherId(user.getUserId());
                List<FormalTeacherClassVo> flVoList = formalTeacherClassService.queryList(ftbo);
                List<String> disciplineName = flVoList.stream().map(FormalTeacherClassVo::getDiscipline).collect(Collectors.toList());
                maekers(courseTableList, disciplineName);
            }
        }

        return TableDataInfo.build(groupedList);
    }

    @SneakyThrows
    @Override
    public TableDataInfo<List<CourseTableVo>> queryPagePcList(CourseTableBo bo, PageQuery pageQuery) {
        if (StringUtils.isEmpty(bo.getClassId()) || StringUtils.isEmpty(bo.getSchoolId())) {
            return TableDataInfo.build(new ArrayList<>());
        }
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(bo);
        Page<CourseTableVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<CourseTableVo> courseTableList = result.getRecords();


        Map<String, List<CourseTableVo>> groupedByType = courseTableList.stream().collect(Collectors.groupingBy(CourseTableVo::getWeek));

        List<List<CourseTableVo>> groupedList = new ArrayList<>(groupedByType.values());

        //获取本周一和本周五的时间
        String fist = DateUtils.getTimeIntervalOne(new Date());
        String five = DateUtils.getTimeIntervalFive(fist);
        List<CourseChangeVo> courseChangeList = courseChangeMapper.selectCourseChangeListByEdit(bo.getClassId(), fist, five);
        if (courseChangeList != null && courseChangeList.size() > 0) {
            for (List<CourseTableVo> courseTableVos : groupedList) {
                //将修改后的课程放入当前周课表
                changeCourseTable(courseTableVos, courseChangeList, fist, five);
            }

            //如果当前角色是老师，获取老师的课程
            LoginUser user = LoginHelper.getLoginUser();
            List<RoleDTO> roles = user.getRoles();
            boolean bl = false;
            for (RoleDTO role : roles) {
                if ("teacher".equals(role.getRoleKey())) {
                    bl = true;
                    break;
                }
            }
            if (bl) {
                //查询老师当前班级所带的课
                FormalTeacherClassBo ftbo = new FormalTeacherClassBo();
                ftbo.setClassId(Long.valueOf(bo.getClassId()));
                ftbo.setTeacherId(user.getUserId());
                List<FormalTeacherClassVo> flVoList = formalTeacherClassService.queryList(ftbo);
                List<String> disciplineName = flVoList.stream().map(FormalTeacherClassVo::getDiscipline).collect(Collectors.toList());

                maekers(courseTableList, disciplineName);
            }
        }

        return TableDataInfo.build(groupedList);
    }

    /**
     * 根据时间查询课表
     *
     * @return
     */
    @SneakyThrows
    @Override
    public R<List<CourseTableVo>> dataCourse(CourseTableBo bo) {
        //判断传入的时间是周几
        int dayForWeek = DateUtils.dayForWeek(bo.getData());
        bo.setWeek(Integer.toString(dayForWeek));
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(bo);
        List<CourseTableVo> CourseTableVoList = baseMapper.selectCourseVoList(lqw);
        return R.ok(CourseTableVoList);
    }

    @Override
    public int deleteWithValidBySchoolId(String schoolId, String classId, String week) {
        CourseTableBo bo = new CourseTableBo();
        bo.setSchoolId(schoolId);
        bo.setClassId(classId);
        bo.setWeek(week);
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(bo);
        return baseMapper.delete(lqw);
    }


    private void maekers(List<CourseTableVo> courseTableList, List<String> disciplineName) {
        //判断老师所带的课程
        for (CourseTableVo table : courseTableList) {
            table.setTeacherClassName(disciplineName);
            Set<Long> teacherClassNum = new HashSet<>();
            if (disciplineName.contains(table.getCourseName())) {
                table.setTeacherType(true);
            }
        }
    }

    @SneakyThrows
    private void changeCourseTable(List<CourseTableVo> courseTableVos, List<CourseChangeVo> courseChangeList, String fist, String five) {
        String format = "yyyy-MM-dd";
        Set<Long> classNum = new HashSet<>();
        for (CourseChangeVo courseChange : courseChangeList) {
            //调课的时间是否在本周
            if (DateUtils.isClass(fist, five, DateUtils.dateTime(courseChange.getSubjectTime()), format)) {
                for (CourseTableVo courseTableVo : courseTableVos) {
                    if (StringUtils.equals(courseChange.getSubjectWeek(), courseTableVo.getWeek()) && StringUtils.equals(Long.toString(courseTableVo.getClassNumber()), courseChange.getIsNum()) && StringUtils.equals(courseTableVo.getTimeFrame(), courseChange.getIsFrame())) {
                        classNum.add(Long.valueOf(courseChange.getIsNum()));
                        courseTableVo.setCourseName(courseChange.getBeSubject());
                        courseTableVo.setCourseTeacher(courseChange.getBePersonnel());
                        courseTableVo.setClassType(true);
                    }
                    if (StringUtils.equals(courseChange.getSubjectWeek(), courseTableVo.getWeek()) && StringUtils.equals(Long.toString(courseTableVo.getClassNumber()), courseChange.getBeIsNum()) && StringUtils.equals(courseTableVo.getTimeFrame(), courseChange.getBeIsFrame())) {
                        classNum.add(Long.valueOf(courseChange.getBeIsNum()));
                        courseTableVo.setCourseName(courseChange.getSubject());
                        courseTableVo.setCourseTeacher(courseChange.getApplyName());
                        courseTableVo.setClassType(true);
                    }
                }
            }
            //被调课是否在本周
            if (DateUtils.isClass(fist, five, DateUtils.dateTime(courseChange.getBeSubjectTime()), format)) {
                for (CourseTableVo courseTableVo : courseTableVos) {
                    if (StringUtils.equals(courseChange.getSubjectWeek(), courseTableVo.getWeek()) && StringUtils.equals(Long.toString(courseTableVo.getClassNumber()), courseChange.getBeIsNum()) && StringUtils.equals(courseTableVo.getTimeFrame(), courseChange.getBeIsFrame())) {
                        classNum.add(Long.valueOf(courseChange.getBeIsNum()));
                        courseTableVo.setCourseName(courseChange.getSubject());
                        courseTableVo.setCourseTeacher(courseChange.getApplyName());
                        courseTableVo.setClassType(true);
                    }
                }
            }
        }
    }


    /**
     * 查询课程列表
     */
    @Override
    public List<CourseTableVo> queryList(CourseTableBo bo) {
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<CourseTable> buildQueryWrapper(CourseTableBo bo) {
        StringBuilder sb = new StringBuilder();
        sb.append("field(postName,'AM','PM','NIGHT')").toString();
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<CourseTable> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getSchoolId()), CourseTable::getSchoolId, bo.getSchoolId());
        lqw.like(StringUtils.isNotBlank(bo.getSchoolName()), CourseTable::getSchoolName, bo.getSchoolName());
        lqw.eq(StringUtils.isNotBlank(bo.getClassId()), CourseTable::getClassId, bo.getClassId());
        lqw.like(StringUtils.isNotBlank(bo.getClassName()), CourseTable::getClassName, bo.getClassName());
        lqw.eq(StringUtils.isNotBlank(bo.getWeek()), CourseTable::getWeek, bo.getWeek());
        lqw.eq(bo.getClassNumber() != null, CourseTable::getClassNumber, bo.getClassNumber());
        lqw.eq(StringUtils.isNotBlank(bo.getTimeFrame()), CourseTable::getTimeFrame, bo.getTimeFrame());
        lqw.eq(StringUtils.isNotBlank(bo.getCourseName()), CourseTable::getCourseName, bo.getCourseName());
        lqw.eq(StringUtils.isNotBlank(bo.getCourseTeacher()), CourseTable::getCourseTeacher, bo.getCourseTeacher());
        lqw.orderByAsc(CourseTable::getTimeFrame);
        lqw.orderByAsc(CourseTable::getClassNumber);
        return lqw;
    }

    /**
     * 新增课程
     */
    @Override
    @Transactional
    public R<Void> insertByBo(CourseTableList boList) {
        int index = 0;
        CourseTableBo table = new CourseTableBo();
        table.setSchoolId(boList.getSchoolId());
        table.setClassId(boList.getClassId());
        table.setWeek(boList.getWeek());
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(table);
        List<CourseTableVo> courseTableList = baseMapper.selectVoList(lqw);
        if (courseTableList != null && courseTableList.size() > 0) {
            return R.fail("当前课表已存在，请前去修改");
        }
        List<CourseTableBo> courseTableBoList = boList.getCourseTableBoList();
        for (CourseTableBo courseTableBo : courseTableBoList) {
            courseTableBo.setSchoolId(boList.getSchoolId());
            courseTableBo.setSchoolName(boList.getSchoolName());
            courseTableBo.setClassId(boList.getClassId());
            courseTableBo.setClassName(boList.getClassName());
            courseTableBo.setWeek(boList.getWeek());
            courseTableBo.setCreateTime(DateUtils.getNowDate());
            CourseTable add = MapstructUtils.convert(courseTableBo, CourseTable.class);
            validEntityBeforeSave(add);
            int i = baseMapper.insert(add);
            if (i > 0) {
                courseTableBo.setId(add.getId());
                index++;
            }
        }
        if (index > 0) {
            return R.ok();
        }
        return R.fail();
    }

    /**
     * 修改课程
     */
    @Override
    @Transactional
    public Boolean updateByBo(CourseTableList boList) {
        CourseTableBo bo = new CourseTableBo();
        bo.setSchoolId(boList.getSchoolId());
        bo.setClassId(boList.getClassId());
        bo.setWeek(boList.getWeek());
        LambdaQueryWrapper<CourseTable> lqw = buildQueryWrapper(bo);
        baseMapper.delete(lqw);
        int index = 0;
        List<CourseTableBo> courseTableBoList = boList.getCourseTableBoList();
        for (CourseTableBo courseTableBo : courseTableBoList) {
            courseTableBo.setSchoolId(boList.getSchoolId());
            courseTableBo.setSchoolName(boList.getSchoolName());
            courseTableBo.setClassId(boList.getClassId());
            courseTableBo.setClassName(boList.getClassName());
            courseTableBo.setWeek(boList.getWeek());
            //id不存咋新增
            courseTableBo.setCreateTime(DateUtils.getNowDate());
            CourseTable add = MapstructUtils.convert(courseTableBo, CourseTable.class);
            validEntityBeforeSave(add);
            boolean flag = baseMapper.insert(add) > 0;
            if (flag) {
                courseTableBo.setId(add.getId());
                index++;
            }
        }
        return index > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(CourseTable entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除课程
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @SneakyThrows
    @Override
    public R<Map<String, Object>> now(Long schoolId, Long classId) {
        //SysUser user = SecurityUtils.getLoginUser().getUser();
        Map<String, Object> map = new HashMap<>();
        map.put("teacher", "");
        map.put("subject", "");
        //家长端查询下课时间
        String key = DateUtils.getDate() + ":" + schoolId + ":" + classId;
        //key = 学校id:班级id
        //Redis根据key键，查询对应的值
        String xiakeTime = "";
        String value = RedisUtils.getCacheObject(key);
        if (StringUtils.isNotEmpty(value)) {
            //延迟放学
            String[] split = value.split(":");
            if (!"time".equals(split[1])) {
                //下课时间
                xiakeTime = split[1] + ":" + split[2] + ":" + split[3];
            }

        }
        map.put("time", xiakeTime);
        //获取当前时间
        String nowTime = DateUtils.getTime();
        //判断当天是周几
        int dayForWeek = DateUtils.dayForWeek(nowTime);
        if (dayForWeek == 6 || dayForWeek == 7) {
            return R.ok(map);
        }
        //获取当前账号所属学校时间表
        List<CourseTableTimeVo> courseTableTimeList = courseTableTimeMapper.selectCourseTableTimeBySchoolId(schoolId);
        if (courseTableTimeList == null && courseTableTimeList.size() <= 0) {
            return R.ok(map);
        }
        //返回当前时间所在的课表时间信息
        CourseTableTimeVo courseTableTime = isClass(courseTableTimeList);
        if (ObjectUtils.isEmpty(courseTableTime)) {
            return R.ok(map);
        }
        //获取当前班级课程
        List<CourseTableVo> courseTableList = baseMapper.selectCourseTableByClassIdAndWeek(classId, dayForWeek);
        if (courseTableList == null && courseTableList.size() <= 0) {
            return R.ok(map);
        }
        //获取本周一和本周五的时间
        String fist = DateUtils.getTimeIntervalOne(new Date());
        String five = DateUtils.getTimeIntervalFive(fist);
        List<CourseChangeVo> courseChangeList = courseChangeMapper.selectCourseChangeListByEdit(String.valueOf(classId), fist, five);
        if (courseChangeList != null && courseChangeList.size() > 0) {
            //将修改后的课程放入当前周课表
            changeCourseTable(courseTableList, courseChangeList, fist, five);
        }

        for (CourseTableVo courseTableVo : courseTableList) {
            if (courseTableTime.getClassNumber() == courseTableVo.getClassNumber() && courseTableTime.getTimeFrame().equals(courseTableVo.getTimeFrame())) {
                map.put("teacher", courseTableVo.getCourseTeacher());
                map.put("subject", courseTableVo.getCourseName());
            }

        }
        return R.ok(map);
    }


    @SneakyThrows
    private CourseTableTimeVo isClass(List<CourseTableTimeVo> courseTableTimeList) {
        //获取当前时间
        String nowTime = DateUtils.getNowTime();
        for (CourseTableTimeVo courseTableTimeVo : courseTableTimeList) {
            if (StringUtils.isNotEmpty(courseTableTimeVo.getStartTime()) && DateUtils.isClass(courseTableTimeVo.getStartTime(), courseTableTimeVo.getEndTime(), nowTime, "HH:mm")) {
                return courseTableTimeVo;
            }
        }
        return new CourseTableTimeVo();
    }


}
