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.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.boot.tools.excel.ExcelReader;
import com.qmth.boot.tools.excel.enums.ExcelType;
import com.qmth.boot.tools.excel.model.DataMap;
import com.qmth.exam.reserve.bean.examsite.*;
import com.qmth.exam.reserve.bean.login.LoginUser;
import com.qmth.exam.reserve.bean.stdapply.CategoryVO;
import com.qmth.exam.reserve.cache.impl.ExamSiteCacheService;
import com.qmth.exam.reserve.dao.ExamSiteDao;
import com.qmth.exam.reserve.entity.CategoryEntity;
import com.qmth.exam.reserve.entity.ExamSiteEntity;
import com.qmth.exam.reserve.service.CategoryService;
import com.qmth.exam.reserve.service.ExamSiteService;
import com.qmth.exam.reserve.util.PageUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ExamSiteServiceImpl extends ServiceImpl<ExamSiteDao, ExamSiteEntity> implements ExamSiteService {

    private static final String[] EXCEL_HEADER = new String[]{"考点代码", "考点名称", "所属教学点", "考点地址"};

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private ExamSiteCacheService examSiteCacheService;

    @Override
    public List<CategoryVO> listExamSite(Long teachingId, Boolean flag) {
        flag = flag != null && flag;
        QueryWrapper<ExamSiteEntity> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ExamSiteEntity> lw = wrapper.lambda();
        lw.eq(flag, ExamSiteEntity::getEnable, Boolean.TRUE);
        lw.eq(ExamSiteEntity::getCategoryId, teachingId);
        lw.orderByAsc(ExamSiteEntity::getCode);
        List<ExamSiteEntity> list = this.baseMapper.selectList(wrapper);
        List<CategoryVO> categoryList = new ArrayList<>();
        for (ExamSiteEntity site : list) {
            CategoryVO vo = new CategoryVO();
            vo.setId(site.getId());
            vo.setName(site.getName());
            vo.setCapacity(site.getCapacity());
            categoryList.add(vo);
        }
        return categoryList;
    }

    @Override
    public List<ExamSiteInfo> getExamSiteListForStudent(Long categoryId) {
        LambdaQueryWrapper<ExamSiteEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(ExamSiteEntity::getId, ExamSiteEntity::getName, ExamSiteEntity::getAddress);
        wrapper.eq(ExamSiteEntity::getCategoryId, categoryId);
        wrapper.eq(ExamSiteEntity::getEnable, Boolean.TRUE);
        List<ExamSiteEntity> entities = baseMapper.selectList(wrapper);

        List<ExamSiteInfo> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(entities)) {
            for (ExamSiteEntity entity : entities) {
                ExamSiteInfo info = new ExamSiteInfo();
                info.setExamSiteId(entity.getId());
                info.setExamSiteName(entity.getName());
                info.setExamSiteAddress(entity.getAddress());
                list.add(info);
            }
        }

        return list;
    }

    /**
     * 获取当前考点总容量
     */
    @Override
    public int countExamSiteCapacityById(Long examSiteId) {
        // 当前考点总容量 = ∑考场机房容量
        Integer capacity = baseMapper.countExamSiteCapacityById(examSiteId);
        return capacity != null ? capacity : 0;
    }

    @Override
    public List<ExamSiteCapacityInfo> findAllExamSiteCapacityList() {
        List<ExamSiteCapacityInfo> list = baseMapper.findAllExamSiteCapacityList();
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        list.forEach(e -> e.setCapacity(e.getCapacity() != null ? e.getCapacity() : 0));
        return list;
    }

    @Override
    public PageResult<ExamSiteVO> page(ExamSiteReq req) {
        IPage<ExamSiteVO> iPage = baseMapper.page(new Page<>(req.getPageNumber(), req.getPageSize()),
                req);
        return PageUtil.of(iPage);
    }

    @Override
    public void saveExamSite(LoginUser user, ExamSiteSaveReq req) {
        checkExamSite(req);
        ExamSiteEntity site = new ExamSiteEntity();
        BeanUtils.copyProperties(req, site);
        site.setCategoryId(req.getTeachingId());
        new ExamSiteEntity();
        ExamSiteEntity beforeUpdateSite;
        if (req.getId() == null) {
            site.setCapacity(0);
            site.setEnable(Boolean.TRUE);
            save(site);
        } else {
            beforeUpdateSite = getById(req.getId());
            updateById(site);
            //更新教学点的容量
            if (!req.getTeachingId().equals(beforeUpdateSite.getCategoryId())) {
                categoryService.updateTeachingCapacity(req.getTeachingId());
                categoryService.updateTeachingCapacity(beforeUpdateSite.getCategoryId());
            }
            //清空考点缓存
            examSiteCacheService.clearExamSiteByIdCache(site.getId());
        }


    }

    @Transactional
    @Override
    public void enable(Long id, Boolean enable) {
        ExamSiteEntity examSite = getById(id);
        examSite.setEnable(enable);
        baseMapper.updateById(examSite);
        //更新教学点的容量
        categoryService.updateTeachingCapacity(examSite.getCategoryId());
    }

    @Transactional
    @Override
    public List<Map<String, Object>> importExamSite(LoginUser user, InputStream inputStream) {
        List<DataMap> lineList = null;
        ExcelReader reader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
        try {
            lineList = reader.getDataMapList();
        } catch (Exception e) {
            throw new StatusException("Excel 解析失败");
        }
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(lineList)) {
            throw new StatusException("Excel无内容");
        }
        List<Map<String, Object>> failRecords = new ArrayList<>();
        List<ExamSiteEntity> examSiteList = new ArrayList<>();
        for (int i = 0; i < lineList.size(); i++) {
            DataMap line = lineList.get(i);
            ExamSiteEntity site = new ExamSiteEntity();
            StringBuilder msg = new StringBuilder();
            String code = trimAndNullIfBlank(line.get(EXCEL_HEADER[0]));
            if (StringUtils.isBlank(code)) {
                msg.append(" 考点代码不能为空");
            } else if (code.length() > 20) {
                msg.append(" 考点代码不能超过20个字符");
            } else {
                site.setCode(code);
            }
            String name = trimAndNullIfBlank(line.get(EXCEL_HEADER[1]));
            if (StringUtils.isBlank(name)) {
                msg.append(" 考点名称不能为空");
            } else if (name.length() > 50) {
                msg.append(" 考点名称不能超过50个字符");
            } else {
                List<ExamSiteEntity> examSiteEntities = listExamSiteByName(name);
                if (examSiteEntities != null && !examSiteEntities.isEmpty()) {
                    msg.append(" 考点名称不能重复");
                } else {
                    site.setName(name);
                }
            }
            String teachingName = trimAndNullIfBlank(line.get(EXCEL_HEADER[2]));
            if (StringUtils.isBlank(teachingName)) {
                msg.append(" 所属教学点不能为空");
            } else {
                LambdaQueryWrapper<CategoryEntity> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(CategoryEntity::getName, teachingName);
                wrapper.eq(CategoryEntity::getEnable, Boolean.TRUE);
                wrapper.eq(CategoryEntity::getOrgId, user.getOrgId());
                List<CategoryEntity> list = categoryService.list(wrapper);
                if (list.isEmpty()) {
                    msg.append(" 所属教学点不存在");
                } else if (list.size() > 1) {
                    msg.append(" 所属教学点，查询到多条相同名称的数据");
                } else {
                    site.setCategoryId(list.get(0).getId());
                }
            }

            String address = trimAndNullIfBlank(line.get(EXCEL_HEADER[3]));
            if (StringUtils.isBlank(address)) {
                msg.append(" 考点地址不能为空");
            } else if (address.length() > 100) {
                msg.append(" 考点地址不能超过100个字符");
            } else {
                site.setAddress(address);
            }
            if (msg.length() > 0) {
                failRecords.add(newError(i + 1, msg.toString()));
            } else {
                site.setEnable(Boolean.TRUE);
                examSiteList.add(site);
            }
        }

        if (CollectionUtils.isNotEmpty(failRecords)) {
            return failRecords;
        }

        for (int i = 0; i < examSiteList.size(); i++) {
            ExamSiteEntity examSite = examSiteList.get(i);
            try {
                saveExamSite(examSite);
            } catch (Exception e) {
                failRecords.add(newError(i + 1, " 系统异常"));
                log.error("导入异常", e);
            }
        }
        if (CollectionUtils.isNotEmpty(failRecords)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return failRecords;
        }
        return failRecords;
    }

    private List<ExamSiteEntity> listExamSiteByName(String name) {
        return lambdaQuery().eq(ExamSiteEntity::getName, name).list();
    }

    @Override
    public void updateExamSiteCapacity(Long examSiteId) {
        baseMapper.updateExamSiteCapacity(examSiteId);
    }

    @Override
    public void saveGuide(ExamSiteGuideReq req) {
        ExamSiteEntity examSite = getById(req.getId());
        LambdaUpdateWrapper<ExamSiteEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(ExamSiteEntity::getGuide, req.getGuide());
        updateWrapper.eq(ExamSiteEntity::getId, req.getId());
        update(null, updateWrapper);
    }

    private void saveExamSite(ExamSiteEntity examSite) {
        LambdaQueryWrapper<ExamSiteEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamSiteEntity::getCode, examSite.getCode());
        wrapper.eq(ExamSiteEntity::getCategoryId, examSite.getCategoryId());
        ExamSiteEntity existSite = baseMapper.selectOne(wrapper);
        if (existSite != null) {
            LambdaUpdateWrapper<ExamSiteEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(ExamSiteEntity::getName, examSite.getName());
            updateWrapper.set(ExamSiteEntity::getAddress, examSite.getAddress());
            updateWrapper.eq(ExamSiteEntity::getId, existSite.getId());
            update(null, updateWrapper);
        } else {
            examSite.setCapacity(0);
            examSite.setEnable(Boolean.TRUE);
            save(examSite);
        }
    }

    private void checkExamSite(ExamSiteSaveReq req) {
        if (StringUtils.isEmpty(req.getCode())) {
            throw new StatusException("考点代码不能为空");
        }
        if (StringUtils.isEmpty(req.getName())) {
            throw new StatusException("考点名称不能为空");
        }
        if (StringUtils.isEmpty(req.getAddress())) {
            throw new StatusException("考点地址不能为空");
        }
        if (req.getTeachingId() == null) {
            throw new StatusException("请选择考点所属教学点");
        }
        checkExamSiteExist(req, req.getId() != null);
        checkExamSiteNameExists(req.getId(), req.getName());
    }

    private void checkExamSiteExist(ExamSiteSaveReq req, boolean idFlag) {
        LambdaQueryWrapper<ExamSiteEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamSiteEntity::getCategoryId, req.getTeachingId());
        wrapper.eq(ExamSiteEntity::getCode, req.getCode());
        wrapper.notIn(idFlag, ExamSiteEntity::getId, req.getId());
        ExamSiteEntity existSite = baseMapper.selectOne(wrapper);
        if (existSite != null) {
            throw new StatusException("考点代码:" + req.getCode() + "已经存在");
        }
    }

    private void checkExamSiteNameExists(Long id, String examSiteName) {
        LambdaQueryWrapper<ExamSiteEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamSiteEntity::getName, examSiteName);
        wrapper.notIn(id != null, ExamSiteEntity::getId, id);
        List<ExamSiteEntity> examSiteEntities = baseMapper.selectList(wrapper);
        if (!examSiteEntities.isEmpty()) {
            throw new StatusException(" 考点名称已经存在");
        }
    }

    private String trimAndNullIfBlank(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        return s.trim();
    }

    private Map<String, Object> newError(int lineNum, String msg) {
        Map<String, Object> map = new HashMap<>();
        map.put("lineNum", lineNum);
        map.put("msg", msg);
        return map;
    }

}
