package com.qmth.exam.reserve.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.core.collection.PageResult;
import com.qmth.boot.core.exception.StatusException;
import com.qmth.exam.reserve.bean.applytask.CurrentApplyTaskVO;
import com.qmth.exam.reserve.bean.category.CategoryCacheBean;
import com.qmth.exam.reserve.bean.category.CategoryInfo;
import com.qmth.exam.reserve.bean.login.LoginUser;
import com.qmth.exam.reserve.bean.stdapply.CategoryVO;
import com.qmth.exam.reserve.bean.teaching.TeachingReq;
import com.qmth.exam.reserve.bean.teaching.TeachingVO;
import com.qmth.exam.reserve.cache.impl.ApplyTaskCacheService;
import com.qmth.exam.reserve.cache.impl.CategoryCacheService;
import com.qmth.exam.reserve.dao.CategoryDao;
import com.qmth.exam.reserve.entity.CategoryEntity;
import com.qmth.exam.reserve.enums.CategoryLevel;
import com.qmth.exam.reserve.enums.Role;
import com.qmth.exam.reserve.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    private ApplyTaskCacheService applyTaskCacheService;

    @Autowired
    private CategoryCacheService categoryCacheService;

    @Override
    public List<CategoryVO> listTeaching(LoginUser user) {
        QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<CategoryEntity> lw = wrapper.lambda();
        List<CategoryEntity> categoryList = new ArrayList<>();
        // 学校管理员
        if (user.getRole().equals(Role.ADMIN)) {
            lw.eq(CategoryEntity::getEnable, Boolean.TRUE);
            lw.eq(CategoryEntity::getLevel, CategoryLevel.TEACHING.getValue());
            categoryList = this.getBaseMapper().selectList(wrapper);
        } else if (user.getRole().equals(Role.TEACHING)) { // 教学点管理员
            lw.eq(CategoryEntity::getId, user.getCategoryId());
            categoryList = this.getBaseMapper().selectList(wrapper);
        } else {
            throw new StatusException("用户无权限");
        }
        List<CategoryVO> cgList = new ArrayList<>();
        for (CategoryEntity category : categoryList) {
            CategoryVO cg = new CategoryVO();
            cg.setId(category.getId());
            cg.setName(category.getName());
            cgList.add(cg);
        }

        return cgList;
    }

    /**
     * 获取数据分类列表（树结构）
     */
    @Override
    public List<CategoryInfo> getCategoryTreeForStudent(LoginUser student) {
        if (Role.STUDENT != student.getRole()) {
            throw new StatusException("请使用学生账号登录！");
        }

        List<CategoryInfo> list = new ArrayList<>();

        // 获取当前启用的预约任务
        CurrentApplyTaskVO curApplyTask = applyTaskCacheService.currentApplyTask(student.getOrgId());
        if (curApplyTask == null) {
            return list;
        }

        if (curApplyTask.getOpenApplyStartTime() > System.currentTimeMillis()) {
            // 自主预约截止时间 之前，只能预约本教学点下的考点

            CategoryCacheBean curCategory = categoryCacheService.getCategoryById(student.getCategoryId());
            if (curCategory == null) {
                return list;
            }

            CategoryInfo curInfo = new CategoryInfo();
            curInfo.setId(curCategory.getId());
            curInfo.setName(curCategory.getName());
            curInfo.setLevel(curCategory.getLevel());
            curInfo.setParentId(curCategory.getParentId());
            curInfo.setSubNodes(new ArrayList<>());

            // 根节点
            CategoryInfo root = this.fillParentCategory(curInfo);
            list.add(root);

            return list;
        }

        // 开放式预约时间，可以在不同教学点间预约
        LambdaQueryWrapper<CategoryEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CategoryEntity::getOrgId, student.getOrgId());
        wrapper.eq(CategoryEntity::getEnable, Boolean.TRUE);
        List<CategoryEntity> categoryList = baseMapper.selectList(wrapper);

        Map<Long, List<CategoryEntity>> categoryMaps = categoryList.stream()
                .collect(Collectors.groupingBy(CategoryEntity::getParentId));
        for (CategoryEntity curEntity : categoryList) {
            if (curEntity.getLevel() > 1) {
                continue;
            }

            // 从根节点开始封装
            CategoryInfo curInfo = new CategoryInfo();
            curInfo.setId(curEntity.getId());
            curInfo.setName(curEntity.getName());
            curInfo.setLevel(curEntity.getLevel());
            curInfo.setParentId(curEntity.getParentId());
            this.fillSubCategory(curInfo, categoryMaps);

            list.add(curInfo);
        }

        return list;
    }

    /**
     * 递归封装子级分类
     */
    private void fillSubCategory(CategoryInfo cur, Map<Long, List<CategoryEntity>> categoryMaps) {
        List<CategoryInfo> subNodes = new ArrayList<>();

        if (categoryMaps.containsKey(cur.getId())) {
            categoryMaps.get(cur.getId()).forEach(entity -> {
                CategoryInfo info = new CategoryInfo();
                info.setId(entity.getId());
                info.setName(entity.getName());
                info.setLevel(entity.getLevel());
                info.setParentId(entity.getParentId());
                this.fillSubCategory(info, categoryMaps);
                subNodes.add(info);
            });
        }

        cur.setSubNodes(subNodes);
    }

    /**
     * 递归封装父级分类
     */
    private CategoryInfo fillParentCategory(CategoryInfo cur) {
        if (cur.getLevel() <= 1) {
            // 根节点，直接返回
            return cur;
        }

        CategoryCacheBean parent = categoryCacheService.getCategoryById(cur.getParentId());
        if (parent == null) {
            return cur;
        }

        CategoryInfo info = new CategoryInfo();
        info.setId(parent.getId());
        info.setName(parent.getName());
        info.setLevel(parent.getLevel());
        info.setParentId(parent.getParentId());

        List<CategoryInfo> subNodes = new ArrayList<>();
        subNodes.add(cur);
        info.setSubNodes(subNodes);

        return fillParentCategory(info);
    }

    @Override
    public PageResult<TeachingVO> page(TeachingReq req) {
        return null;
    }

}
