package com.unis.module.coding.service.task;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yitter.idgen.YitIdHelper;
import com.unis.framework.common.pojo.PageParam;
import com.unis.framework.common.util.object.BeanUtils;
import com.unis.framework.security.core.LoginUser;
import com.unis.framework.security.core.util.SecurityFrameworkUtils;
import com.unis.module.coding.controller.admin.task.vo.*;
import com.unis.module.coding.dal.dataobject.bank.BankDO;
import com.unis.module.coding.dal.dataobject.cwxx.CwxxDO;
import com.unis.module.coding.dal.dataobject.cwxxyear.CwxxYearDO;
import com.unis.module.coding.dal.dataobject.dk.DkDO;
import com.unis.module.coding.dal.dataobject.dwxx.DwxxDO;
import com.unis.module.coding.dal.dataobject.kqxx.KqxxDO;
import com.unis.module.coding.dal.dataobject.province.ProvinceDO;
import com.unis.module.coding.dal.dataobject.users.UsersDO;
import com.unis.module.coding.dal.mysql.bank.BankMapper;
import com.unis.module.coding.dal.mysql.cwxx.CwxxMapper;
import com.unis.module.coding.dal.mysql.cwxxyear.CwxxYearMapper;
import com.unis.module.coding.dal.mysql.dk.DkMapper;
import com.unis.module.coding.dal.mysql.dwxx.DwxxMapper;
import com.unis.module.coding.dal.mysql.kqxx.KqxxMapper;
import com.unis.module.coding.dal.mysql.province.ProvinceMapper;
import com.unis.module.coding.dal.mysql.users.UsersMapper;
import com.unis.module.core.enums.ErrorCodeConstants;
import com.unis.module.core.enums.project.DeliveryHyState;
import com.unis.module.system.api.permission.PermissionApi;
import com.unis.module.system.enums.permission.RoleCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

import static com.unis.framework.common.exception.util.ServiceExceptionUtil.exception;


/**
 * app Service 实现类
 *
 * @author duhuajie
 */
@Service
@Validated
@Slf4j
public class TaskServiceImpl implements TaskService {

    @Resource
    private DkMapper dkMapper;
    @Resource
    private PermissionApi permissionApi;
    @Resource
    private ProvinceMapper provinceMapper;
    @Resource
    private KqxxMapper kqxxMapper;
    @Resource
    private DwxxMapper dwxxMapper;
    @Resource
    private CwxxMapper cwxxMapper;
    @Resource
    private CwxxYearMapper cwxxYearMapper;
    @Resource
    private BankMapper bankMapper;
    @Resource
    private UsersMapper usersMapper;

    @Override
    public IPage<TaskRespVO> getTaskList(TaskPageReqVO pageReqVO) {
        // 根据角色不同，查询不同数据
        addParamDeptIds(pageReqVO);

        IPage<TaskRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        return dkMapper.getTaskList(page, pageReqVO);
    }

    @Override
    public IPage<TaskRespVO> getAllStoreroomList(TaskPageReqVO pageReqVO) {
        // 根据角色不同，查询不同数据
        addParamDeptIds(pageReqVO);

        IPage<TaskRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        return dkMapper.getAllStoreroomList(page, pageReqVO);
    }

    @Override
    public IPage<TaskRespVO> getMyStoreroomList(TaskPageReqVO pageReqVO) {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserIdNotNull();
        // 查询登录人角色标识
        Set<String> roleCodes = permissionApi.getUserRoleCodeListByUserIdFromCache(loginUserId);

        // 存粮人
        if(!roleCodes.contains(RoleCodeEnum.GRAIN_DEPOSITOR.getCode())) {
            throw exception(ErrorCodeConstants.APP_ACCOUNT_PERMISSION_DENIED);
        }

        pageReqVO.setCreator(String.valueOf(loginUserId));
        IPage<TaskRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        return dkMapper.getMyStoreroomList(page, pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean getTasks(TaskPageReqVO reqVO) {

        //校验是登录人可选的任务
        verifyTask(reqVO);

        Long loginUserId = SecurityFrameworkUtils.getLoginUserIdNotNull();
        // 查询登录人角色标识
        Set<String> roleCodes = permissionApi.getUserRoleCodeListByUserIdFromCache(loginUserId);

        // 更新核验状态为核验中,核验人员 id,核验人员名
        // 省级核验人员
        if(roleCodes.contains(RoleCodeEnum.PROVINCIAL_VERIFICATION_PERSONNEL.getCode())) {
            reqVO.getKqIds().forEach(kqId -> {
                ProvinceDO provinceDO = new ProvinceDO()
                        .setHyState(reqVO.getHyState())
                        .setHyryId(SecurityFrameworkUtils.getLoginUserId())
                        .setHyryName(SecurityFrameworkUtils.getLoginUserNickname());
                provinceMapper.updateByKqId(provinceDO, kqId);
            });
        }
        // 银行核验人员
        if(roleCodes.contains(RoleCodeEnum.BANK_VERIFICATION_PERSONNEL.getCode())) {
            reqVO.getKqIds().forEach(kqId -> {
                BankDO bankDO = new BankDO()
                        .setHyState(reqVO.getHyState())
                        .setHyryId(SecurityFrameworkUtils.getLoginUserId())
                        .setHyryName(SecurityFrameworkUtils.getLoginUserNickname());
                bankMapper.updateByKqId(bankDO, kqId);
            });
        }
        return true;
    }

    @Override
    public Boolean getStoreroom(TaskPageReqVO reqVO) {
        if(reqVO.getCaIds() == null || reqVO.getCaIds().isEmpty()){
            throw exception(ErrorCodeConstants.APP_PARAM_ERROR_STORAGE);
        }

        // 存粮人选定仓 新增数据 以仓房为单位
        if(reqVO.getClrsfxd() != null && 0 == reqVO.getClrsfxd()) {
            //存粮人删除选定
            reqVO.getCaIds().forEach(caId ->
                    usersMapper.delete(new QueryWrapper<UsersDO>().lambda()
                            .eq(UsersDO::getCreator, SecurityFrameworkUtils.getLoginUserId())
                            .eq(UsersDO::getCaId, caId)));

        } else {
            // 校验 是登录人可选的任务
            List<TaskCaxxRespVO> taskCaxxRespVOS = verifyStoreroom(reqVO);

            taskCaxxRespVOS.forEach(taskCaxxRespVO ->
                    usersMapper.insert(new UsersDO()
                            .setId(YitIdHelper.nextId())
                            .setKqId(taskCaxxRespVO.getKqId())
                            .setCaId(taskCaxxRespVO.getCaId())));
        }

        return true;
    }

    @Override
    public List<TaskCaxxRespVO> getCaxxByKqId(TaskPageReqVO reqVO) {
        // 根据角色不同，查询不同数据
        addParamDeptIds(reqVO);

        return dkMapper.selectCaxxListByKqId(reqVO);
    }

    @Override
    public List<TaskCaxxRespVO> getCaxxByKqIdForClr(TaskPageReqVO reqVO) {
        // 根据角色不同，查询不同数据
        addParamDeptIds(reqVO);

        return dkMapper.getCaxxByKqIdForClr(reqVO);
    }

    @Override
    public TaskKqxxRespVO getKqxxByKqId(TaskPageReqVO reqVO) {

        KqxxDO kqxxDO = kqxxMapper.selectById(reqVO.getKqId());

        if(ObjectUtils.isNotEmpty(kqxxDO)) {

            //单位信息
            DwxxDO dwxxDO = dwxxMapper.selectById(kqxxDO.getDwid());

            TaskKqxxRespVO kqxx = BeanUtils.toBean(kqxxDO, TaskKqxxRespVO.class);
            kqxx.setDwmc(dwxxDO.getDwmc());
            kqxx.setTyxydm(dwxxDO.getTyxydm());
            kqxx.setQyxz(dwxxDO.getQyxz());
            kqxx.setJd(dwxxDO.getJd());
            kqxx.setWd(dwxxDO.getWd());

            // 账号信息
//            AdminUserDO user = userService.getUserByKqbm(kqxxDO.getKqbm());
//            if(ObjectUtils.isNotEmpty(user)){
//                kqxx.setUserId(user.getId());
//                kqxx.setUsername(user.getUsername());
//                kqxx.setPassword(user.getPassword());
//            }
            return kqxx;
        }

        return null;
    }

    @Override
    public TaskCwxxRespVO getCwxxByKqId(TaskPageReqVO reqVO) {

        CwxxDO cwxxDO = cwxxMapper.selectByKqId(reqVO.getKqId());

        if(ObjectUtils.isEmpty(cwxxDO)) {
            return null;
        }

        List<CwxxYearDO> cnxxList = cwxxYearMapper.selectByCwxxId(cwxxDO.getId());

        TaskCwxxRespVO cwxxRespVO = BeanUtils.toBean(cwxxDO, TaskCwxxRespVO.class);

        cwxxRespVO.setCnxxList(BeanUtils.toBean(cnxxList, TaskCnxxRespVO.class));

        return cwxxRespVO;
    }

    @Override
    public TaskDkxxRespVO getDkxxByKqId(TaskPageReqVO reqVO) {
        DkDO dkDO = dkMapper.selectByKqIdAndUserId(reqVO.getKqId(), SecurityFrameworkUtils.getLoginUserId());

        if(ObjectUtils.isEmpty(dkDO)) {
            return null;
        }
        return BeanUtils.toBean(dkDO, TaskDkxxRespVO.class);
    }

    /**
     * 打卡(传 id 是变更(传图片),不传 id 是新增
     * @param saveVO 打卡对象
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskDkxxRespVO setDkxxByKqId(TaskDkxxSaveVO saveVO) {

        if(ObjectUtils.isEmpty(saveVO) || ObjectUtils.isEmpty(saveVO.getKqId())) {
            throw exception(ErrorCodeConstants.APP_PARAM_ERROR);
        }
        Long loginUserId = SecurityFrameworkUtils.getLoginUserIdNotNull();
        DkDO dkDO = dkMapper.selectByKqIdAndUserId(saveVO.getKqId(), loginUserId);
        synchronized (loginUserId){ //上锁 避免重复提交
            if(ObjectUtils.isEmpty(saveVO.getId())) {
                if(ObjectUtils.isNotEmpty(dkDO)) {
                    throw exception(ErrorCodeConstants.APP_TASK_RECEIVE_ERROR_RETRY);
                }

                // 查询登录人角色标识,填充[打卡类型]
                setDkType(saveVO, loginUserId);

                //新增
                DkDO saveDo = getDkDO(saveVO, loginUserId);
                dkMapper.insert(saveDo);
                return BeanUtils.toBean(saveDo, TaskDkxxRespVO.class); //返回打卡对象
            } else {
                //变更
                if(ObjectUtils.isNotEmpty(dkDO) && dkDO.getId().equals(saveVO.getId())) {
                    DkDO updateDo = BeanUtils.toBean(saveVO, DkDO.class);
                    updateDo.setDksj(LocalDateTime.now());
                    dkMapper.updateById(updateDo);
                    return BeanUtils.toBean(updateDo, TaskDkxxRespVO.class);
                } else {
                    throw exception(ErrorCodeConstants.APP_PARAM_ERROR);
                }
            }
        }
    }

    @Override
    public TaskHwkRespVO getHwkByCfId(Long cfId) {
        return dkMapper.getHwkByCfId(cfId);
    }

    @Override
    public TaskSyxxRespVO getSyxxByCfId(Long cfId) {
        return dkMapper.getSyxxByCfId(cfId);
    }

    @Override
    public TaskLqjcxxRespVO getLqjcxxByCfId(Long cfId) {
        return dkMapper.getLqjcxxByCfId(cfId);
    }

    @Override
    public IPage<TaskCrkxxRespVO> getCrkxxByCfId(TaskPageReqVO pageReqVO) {
        IPage<TaskCrkxxRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        return dkMapper.getCrkxxByCfId(page, pageReqVO);
    }

    @Override
    public IPage<TaskZjxxRespVO> getZjxxByCfId(TaskPageReqVO pageReqVO) {
        IPage<TaskZjxxRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        return dkMapper.getZjxxByCfId(page, pageReqVO);
    }

    @NotNull
    private static DkDO getDkDO(TaskDkxxSaveVO saveVO, Long loginUserId) {
        DkDO saveDo = BeanUtils.toBean(saveVO, DkDO.class);
        saveDo.setId(YitIdHelper.nextId());// 雪花id
        saveDo.setUserId(loginUserId);
        saveDo.setDksj(LocalDateTime.now());
        return saveDo;
    }

    private void setDkType(TaskDkxxSaveVO saveVO, Long loginUserId) {
        Set<String> roleCodes = permissionApi.getUserRoleCodeListByUserIdFromCache(loginUserId);

        if(roleCodes.contains(RoleCodeEnum.PROVINCIAL_VERIFICATION_PERSONNEL.getCode())) {
            saveVO.setDkType(TaskDkxxSaveVO.PROVINCIAL_VERIFICATION_PERSONNEL_DK_TYPE);
        } else if(roleCodes.contains(RoleCodeEnum.BANK_VERIFICATION_PERSONNEL.getCode())) {
            saveVO.setDkType(TaskDkxxSaveVO.VERIFICATION_PERSONNEL_DK_TYPE);
        } else {
            throw exception(ErrorCodeConstants.APP_ACCOUNT_PERMISSION_DENIED);
        }
    }

    private void verifyTask(TaskPageReqVO reqVO) {
        if(reqVO.getKqIds() == null || reqVO.getKqIds().isEmpty()
                || reqVO.getHyState() == null || reqVO.getListType() == null){
            throw exception(ErrorCodeConstants.APP_PARAM_ERROR);
        }

        TaskPageReqVO pageReqVO = new TaskPageReqVO();
        pageReqVO.setKqIds(reqVO.getKqIds());
        pageReqVO.setListType(reqVO.getListType());
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);

        IPage<TaskRespVO> taskList = getTaskList(pageReqVO);

        if(taskList.getRecords().size() != reqVO.getKqIds().size()) {
            throw exception(ErrorCodeConstants.APP_TASK_RECEIVE_ERROR);
        }
    }

    private List<TaskCaxxRespVO> verifyStoreroom(TaskPageReqVO reqVO) {

        TaskPageReqVO pageReqVO = new TaskPageReqVO();
        pageReqVO.setCaIds(reqVO.getCaIds());
        pageReqVO.setListType(TaskPageReqVO.LIST_TYPE_TASK3);
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);

        List<TaskCaxxRespVO> taskList = getCaxxByKqIdForClr(pageReqVO);

        if(taskList.size() != reqVO.getCaIds().size()) {
            throw exception(ErrorCodeConstants.APP_TASK_RECEIVE_ERROR);
        }
        return taskList;
    }

    private void addParamDeptIds(@NotNull TaskPageReqVO pageReqVO) {

        Long loginUserId = SecurityFrameworkUtils.getLoginUserIdNotNull();
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        // 查询登录人角色标识
        Set<String> roleCodes = permissionApi.getUserRoleCodeListByUserIdFromCache(loginUserId);

        // 查询待核验列表
        if(pageReqVO.getListType() == null) {
            throw exception(ErrorCodeConstants.APP_PARAM_ERROR);
        } else if(TaskPageReqVO.LIST_TYPE_TASK1.equals(pageReqVO.getListType())) {
            // 可选任务
            pageReqVO.setHyState(DeliveryHyState.WAIT.getCode());
        } else if(TaskPageReqVO.LIST_TYPE_TASK2.equals(pageReqVO.getListType())) {
            // 已选任务
            pageReqVO.setHyryId(loginUserId);
        } else if(TaskPageReqVO.LIST_TYPE_TASK3.equals(pageReqVO.getListType())) {
            // 存粮人可选列表
            pageReqVO.setHyState(DeliveryHyState.YES_HY.getCode());
            pageReqVO.setClrsfxd(0);
        } else if(TaskPageReqVO.LIST_TYPE_TASK4.equals(pageReqVO.getListType())) {
            // 存粮人已选列表
            pageReqVO.setHyState(DeliveryHyState.YES_HY.getCode());
            pageReqVO.setClrsfxd(1);
            pageReqVO.setCreator(String.valueOf(loginUserId));
        } else {
            throw exception(ErrorCodeConstants.APP_PARAM_ERROR);
        }

        // 省级核验人员
        if(roleCodes.contains(RoleCodeEnum.PROVINCIAL_VERIFICATION_PERSONNEL.getCode())) {
            if(loginUser != null) {
                String areaLevel = loginUser.getInfo().get("areaLevel");
                if("1".equals(areaLevel)) {
                    pageReqVO.setSheng(loginUser.getInfo().get("shengCode"));
                    pageReqVO.setTableName(TaskPageReqVO.TABLE_NAME_DELIVERY_PROVINCE);
                } else {
                    throw exception(ErrorCodeConstants.APP_ACCOUNT_PERMISSION_DENIED);
                }
            }
            return;
        }
        // 银行核验人员 | 存粮人
        if(roleCodes.contains(RoleCodeEnum.BANK_VERIFICATION_PERSONNEL.getCode()) ||
                roleCodes.contains(RoleCodeEnum.GRAIN_DEPOSITOR.getCode())) {
            if(loginUser != null) {
                pageReqVO.setBankType(loginUser.getInfo().get("bankType"));
                pageReqVO.setTableName(TaskPageReqVO.TABLE_NAME_DELIVERY_BANK);
            }
            return;
        }

        throw exception(ErrorCodeConstants.APP_ACCOUNT_PERMISSION_DENIED);
    }
}