package com.chushang.inspection.work.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chushang.common.core.constant.SecurityConstants;
import com.chushang.common.core.exception.ResultException;
import com.chushang.common.core.exception.utils.AssertUtil;
import com.chushang.common.core.util.DateUtils;
import com.chushang.common.core.util.IPUtils;
import com.chushang.common.core.util.SpringUtils;
import com.chushang.common.core.web.Result;
import com.chushang.common.dict.utils.DictUtils;
import com.chushang.common.excel.utils.ExcelUtils;
import com.chushang.common.mybatis.enums.Operator;
import com.chushang.common.mybatis.page.CommonParam;
import com.chushang.common.mybatis.utils.PageResult;
import com.chushang.common.mybatis.utils.WrapperUtils;
import com.chushang.inspection.ins.GeneratedInsFactory;
import com.chushang.inspection.project.dto.AuditDTO;
import com.chushang.inspection.project.po.InspectionData;
import com.chushang.inspection.project.service.InspectionDataService;
import com.chushang.inspection.project.service.PollingTaskService;
import com.chushang.inspection.project.vo.CountVO;
import com.chushang.inspection.terminal.po.FiveStore;
import com.chushang.inspection.terminal.po.Store;
import com.chushang.inspection.terminal.po.Terminal;
import com.chushang.inspection.terminal.po.TerminalIns;
import com.chushang.inspection.terminal.service.*;
import com.chushang.inspection.terminal.vo.FiveStoreVO;
import com.chushang.inspection.utils.PoolUtils;
import com.chushang.inspection.utils.TaskConfigUtils;
import com.chushang.inspection.work.dto.WrkInfoDTO;
import com.chushang.inspection.work.enums.WorkTypeOperation;
import com.chushang.inspection.work.po.*;
import com.chushang.inspection.work.query.DispatchQuery;
import com.chushang.inspection.work.query.ReviewedQuery;
import com.chushang.inspection.work.query.WrkAppQuery;
import com.chushang.inspection.work.query.WrkInfoQuery;
import com.chushang.inspection.work.service.*;
import com.chushang.inspection.work.vo.*;
import com.chushang.security.utils.SecurityUtils;
import com.chushang.system.feign.RemoteDeptService;
import com.chushang.task.entity.dto.CreateTaskDTO;
import com.chushang.task.enums.ServiceEnum;
import com.chushang.task.enums.TaskTypeEnum;
import com.chushang.task.feign.RemoteTaskService;
import com.chushang.security.entity.po.SysUser;
import com.chushang.system.feign.RemoteUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chushang.inspection.work.mapper.WrkInfoMapper;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @auther: zhao
 * @date: 2024/6/26 17:13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WrkInfoServiceImpl extends ServiceImpl<WrkInfoMapper, WrkInfo> implements WrkInfoService {

    private final WrkImgService wrkImgService;

    private final WrkInfoStoreRecordService wrkInfoStoreRecordService;
    private final WrkInfoTerminalRecordService wrkInfoTerminalRecordService;
    private final WrkInfoTerminalInsRecordService wrkInfoTerminalInsRecordService;

    private final FiveStoreService fiveStoreService;

    private final StoreService storeService;
    private final TerminalService terminalService;
    private final TerminalInsService terminalInsService;

    private final GeneratedInsFactory generatedInsFactory;
    private final PollingTaskService pollingTaskService;
    private final WrkInfoDispatchService dispatchService;

    private final WrkInfoAuditService infoAuditService;
    private final InspectionDataService inspectionDataService;
    private final RemoteTaskService remoteTaskService;
    private final RemoteUserService userFeignService;
    private final RemoteDeptService remoteDeptService;
    private final DispatchRecordService dispatchRecordService;

    @Value("${push.icbc-js.enable:false}")
    private boolean enable;

    @Override
    public void exportDispatchPage(HttpServletResponse response, WrkInfoQuery query) {
        WrapperUtils.buildSql(query);
        List<WrkInfoExportVO> records = baseMapper.exportDispatchPage(query);
        ExcelUtils.exportList(response, WrkInfoExportVO.class, records, "导出派单");
    }


    @Override
    public PageResult queryDispatchPage(WrkInfoQuery query) {
        CommonParam commonParam = CommonParam.buildPageRequest();
        WrapperUtils.buildSql(query);
        Page<WrkInfoDetailsVO> page = new Page<>(commonParam.getPage(), commonParam.getLimit());
        List<WrkInfoDetailsVO> records = baseMapper.queryDispatchPage(query, page);
        return new PageResult(records, page);
    }

    @Override
    public PageResult queryArchivePage(ReviewedQuery query) {
        CommonParam commonParam = CommonParam.buildPageRequest();
        WrapperUtils.buildSql(query);
        Page<WrkInfoDetailsVO> page = new Page<>(commonParam.getPage(), commonParam.getLimit());
        List<WrkInfoDetailsVO> records = baseMapper.queryArchivePage(query, page);
        return new PageResult(records, page);
    }

    /**
     * app查询 工单列表
     */
    @Override
    public PageResult queryAppPage(WrkAppQuery query) {
        WrapperUtils.buildSql(query);
        CommonParam commonParam = CommonParam.buildPageRequest();
        Page<WrkListAppVO> page = new Page<>(commonParam.getPage(), commonParam.getLimit());
        List<WrkListAppVO> records = baseMapper.queryAppPage(query, page);
        return new PageResult(records, page);
    }

    @Override
    public WrkInfoDetailsVO queryWorkOrderDetails(Long wrkId) {
//        // 终端信息
//        WrkInfoTerminalRecord terminalRecord = terminalRecordService.getById(wrkId);
//        // 商户信息
//        WrkInfoStoreRecord storeRecord = storeRecordService.getById(wrkId);
//        // 工单信息
//        WrkInfo wrkInfo = getById(wrkId);
//        infoDetail.setInfoTerminal(BeanUtil.copyProperties(terminalRecord, WrkInfoTerminalVO.class));
//        infoDetail.setInfoStore(BeanUtil.copyProperties(storeRecord, WrkInfoStoreVO.class));
//        infoDetail.setWrkInfo(BeanUtil.copyProperties(wrkInfo, WrkInfoVO.class));
        // 商户信息, 终端信息, 工单信息
        WrkInfoDetailsVO infoDetail = baseMapper.getWrkInfoDetails(wrkId);
        WrkInfoVO wrkInfo = infoDetail.getWrkInfo();
        if (ObjectUtil.isEmpty(wrkInfo)) return infoDetail;
        WrkInfoTerminalVO terminal = infoDetail.getInfoTerminal();
        // 工单审核
        List<WrkInfoAudit> auditList = infoAuditService.list(new LambdaQueryWrapper<WrkInfoAudit>()
                .eq(WrkInfoAudit::getWrkId, wrkId));
        infoDetail.setInfoAudit(BeanUtil.copyToList(auditList, AuditVO.class));
        // 工单图片
        List<WrkImg> imgList = wrkImgService.list(new LambdaQueryWrapper<WrkImg>().eq(WrkImg::getImgId, wrkId));
        infoDetail.setInfoImg(BeanUtil.copyToList(imgList, WrkImgVO.class));
        // 内蒙古 五统一商户
        if (terminal.getTerminalId() != null && "建行内蒙古".equals(TaskConfigUtils.getConfig(wrkInfo.getTaskId()).getName())) {
            FiveStore fiveStore = fiveStoreService.getOne(new LambdaQueryWrapper<FiveStore>()
                    .eq(FiveStore::getTerminalId, terminal.getTerminalId()).last(Operator.LIMIT_ONE.getCharacter()));
            infoDetail.setFiveStoreDetails(BeanUtil.copyProperties(fiveStore, FiveStoreVO.class));
        }
        // 门头照片
        if (IPUtils.isMobile() && ObjectUtil.equals(wrkInfo.getWrkStatus(), 1) && terminal.getTerminalId() != null) {
            infoDetail.getWrkInfo().setDoorImage(wrkImgService.getOne(new LambdaQueryWrapper<WrkImg>().eq(WrkImg::getWrkId, wrkId).eq(WrkImg::getImgType, -1)
                    .last(Operator.LIMIT_ONE.getCharacter())).getRealPath());
        }
        infoDetail.setInspections(inspectionDataService.listInspections(wrkId));
        return infoDetail;
    }

    @Override
    @Transactional
    public List<WrkInfo> dispatch(DispatchQuery query, int i) {

        AssertUtil.invalidate(CollectionUtil.isNotEmpty(query.getTerminalIds()) && CollectionUtil.isNotEmpty(query.getTerminalNos()),
                "获取终端错误");
        // 获取所有终端信息
        List<Terminal> terminals =  terminalService.list(new LambdaQueryWrapper<Terminal>()
                .in(CollectionUtil.isNotEmpty(query.getTerminalIds()), Terminal::getTerminalId, query.getTerminalIds())
                .or()
                .in(CollectionUtil.isNotEmpty(query.getTerminalNos()), Terminal::getTerminalNo, query.getTerminalNos())
        );
        AssertUtil.invalidate(CollectionUtil.isEmpty(terminals), "您指定派单/领取的终端不存在");
        Set<Long> terminalIds = terminals.stream().map(Terminal::getTerminalId).collect(Collectors.toSet());
        // 获取所有终端附加信息
        List<TerminalIns> terminalIns = terminalInsService.listByIds(terminalIds);
        List<Long> storeIds = terminals.stream().map(Terminal::getStoreId).toList();
        // 商户信息
        List<Store> stores = storeService.listByIds(storeIds);
        // 商户 map
        Map<Long, Store> storeMap
                = stores.stream().collect(Collectors.toMap(Store::getStoreId, s -> s, (o, n) -> n));
        Result<SysUser> userInfo = userFeignService.getInfoById(query.getUserId(), SecurityConstants.INNER);

        Set<Long> deptIds = stores.stream().map(Store::getDeptId).collect(Collectors.toSet());
        Map<Long, String> deptNameMap = remoteDeptService.getDeptNameByIds(deptIds, SecurityConstants.INNER);
        List<WrkInfo> resultList = new ArrayList<>();
        storeMap.forEach((storeId, store) -> {
            List<Terminal> terList
                    = terminals.stream().filter(t -> t.getStoreId().equals(store.getStoreId())).toList();
            List<Long> terIds = terList.stream().map(Terminal::getTerminalId).toList();
            Map<Long, TerminalIns> terInsMap = terminalIns.stream().filter(t -> terIds.contains(t.getTerminalId()))
                    .collect(Collectors.toMap(TerminalIns::getTerminalId, t -> t, (o, n) -> n));

            List<WrkInfo> wrkInfos = this.saveData(store, terList, terInsMap, query, userInfo.getData(), deptNameMap.get(store.getDeptId()));

            // 还需要修改 终端状态信息
            if (!TaskConfigUtils.isRepeat(store.getTaskId())) {
                // 修改 终端占用
                terminalService.updateOccupy(terIds, 1);
            }
            // 新增 派单进度
            dispatchService.updateWorkOrderProgress(query.getUserId(),6, wrkInfos.stream().map(WrkInfo::getWrkId).toList(), store.getDeptId());
            resultList.addAll(wrkInfos);
        });
        return resultList;
    }

    /**
     * 保存工单信息
     */
    private List<WrkInfo> saveData(Store store, List<Terminal> terminals, Map<Long, TerminalIns> terInsMap, DispatchQuery query,SysUser userInfoData, String deptName) {
        Integer method = TaskConfigUtils.dispatchMethod(store.getTaskId());
        // （0 业务员领取 1 只能派给负责项目的业务员 2 只能派给商户对应的客户经理 ）
        return terminals.stream().map(t -> {
            WrkInfo wrkInfo = new WrkInfo();
            wrkInfo.setTaskId(store.getTaskId());
            wrkInfo.setDeptId(store.getDeptId());
            wrkInfo.setUserId(query.getUserId());
            wrkInfo.setAccountPhone(store.getAccountPhone());
            wrkInfo.setAccountManager(store.getAccountManager());
            wrkInfo.setUserName(userInfoData.getNickName());
            wrkInfo.setWorkNo(IdUtil.getSnowflake().nextId());
            wrkInfo.setWorkType(query.getWorkType());
            wrkInfo.setWorkMethod(method);
            wrkInfo.setWorkSort(query.getWorkSort());
            wrkInfo.setWrkStatus(1);
            wrkInfo.setWorkSource(query.getWorkSource());
            wrkInfo.setLowerTaskId(store.getLowerTaskId());
            wrkInfo.setTaskName(pollingTaskService.getTaskNameById(store.getTaskId()));
            wrkInfo.setLowerTaskName(pollingTaskService.getTaskNameById(store.getLowerTaskId()));
            wrkInfo.setVersion(0L);
            wrkInfo.setEndTime(query.getEndTime());
            wrkInfo.setDisSchedule(6);
            wrkInfo.setRegisterTime(LocalDate.now());
            wrkInfo.setDeptName(deptName);
            wrkInfo.setProjectId(store.getProjectId());
            // 处理时间
            save(wrkInfo);

            WrkDispatchRecord wrkDispatchRecord = BeanUtil.copyProperties(t, WrkDispatchRecord.class);
            wrkDispatchRecord.setId(IdUtil.getSnowflake().nextId());
            wrkDispatchRecord.setStoreId(store.getStoreId());
            wrkDispatchRecord.setStoreNo(store.getStoreNo());
            wrkDispatchRecord.setStoreName(store.getStoreName());
            wrkDispatchRecord.setWrkId(wrkInfo.getWrkId());
            wrkDispatchRecord.setWorkNo(wrkInfo.getWorkNo());
            wrkDispatchRecord.setDeptName(deptName);
            wrkDispatchRecord.setDeptId(store.getDeptId());
            wrkDispatchRecord.setTaskId(store.getTaskId());
            wrkDispatchRecord.setLowerTaskId(store.getLowerTaskId());
            wrkDispatchRecord.setTaskName(wrkInfo.getTaskName());
            wrkDispatchRecord.setLowerTaskName(wrkInfo.getLowerTaskName());
            wrkDispatchRecord.setUserId(query.getUserId());
            wrkDispatchRecord.setUserName(wrkInfo.getUserName());
            dispatchRecordService.save(wrkDispatchRecord);

            WrkInfoTerminalRecord wrkInfoTerminalRecord = BeanUtil.copyProperties(t, WrkInfoTerminalRecord.class);
            wrkInfoTerminalRecord.setWrkId(wrkInfo.getWrkId());
            wrkInfoTerminalRecord.setVersion(0L);
            wrkInfoTerminalRecordService.save(wrkInfoTerminalRecord);
            WrkInfoStoreRecord wrkInfoStoreRecord = BeanUtil.copyProperties(store, WrkInfoStoreRecord.class);
            wrkInfoStoreRecord.setWrkId(wrkInfo.getWrkId());
            wrkInfoStoreRecordService.save(wrkInfoStoreRecord);
            TerminalIns terminalIns = terInsMap.get(t.getTerminalId());
            if (ObjectUtil.isNotEmpty(terminalIns)) {
                // 终端巡检信息
                WrkInfoTerminalInsRecord wrkInfoTerminalInsRecord = BeanUtil.copyProperties(terminalIns, WrkInfoTerminalInsRecord.class);
                wrkInfoTerminalInsRecord.setWrkId(wrkInfo.getWrkId());
                wrkInfoTerminalInsRecordService.save(wrkInfoTerminalInsRecord);
            }
            return wrkInfo;
        }).toList();
    }

    @Override
    public Long downInsTemplate(ReviewedQuery query) {
        // 先查询是否存在对应的记录
        WrapperUtils.buildSql(query);
        Page<WrkInfoDetailsVO> page = new Page<>(1, 1);
        baseMapper.queryArchivePage(query, page);
        // 必须 total 大于0, 才走下一步
        AssertUtil.invalidate(page.getTotal() == 0, "下载信息为空");
        DateUtils.format(LocalDate.now());
        // 下载巡检单信息
        Result<Long> task = remoteTaskService.createTask(CreateTaskDTO.builder()
                .params(JSON.toJSONString(query))
                .taskName(DateUtils.format(LocalDate.now()) + "-" + SecurityUtils.getUsername() + "-导出-" + query.getTaskId() + "-巡检单信息")
                .applicationName(ServiceEnum.INSPECTION)
                .methodName("downInspectionTemplate")
                .className(this.getClass().getName())
                .deptId(SecurityUtils.getDeptId())
                .taskType(TaskTypeEnum.DOWN)
                .remark("导出巡检单信息")
                .createBy(SecurityUtils.getUsername())
                .build(), SecurityConstants.INNER);
        if (task.isSuccess() && task.getData() != null) {
            return task.getData();
        }
        throw new ResultException("创建后台任务异常");
    }

    /**
     * 提交工单
     *
     * @param info 工单, 商户信息
     */
    @Override
    public void submit(WrkInfoDTO info) {
        // 获取 任务的审核方式 1 无审核, 2 初审, 3 复审
        Integer reviewMethod = TaskConfigUtils.reviewMethod(info.getTaskId());
        // 工单, 商户, 终端信息
        WrkInfoDetailsVO infoDetail = baseMapper.getWrkInfoDetails(info.getWrkId());
        // 工单
        WrkInfoVO wrkInfo = infoDetail.getWrkInfo();
        // 终端
        WrkInfoTerminalVO infoTerminal = infoDetail.getInfoTerminal();
        // 商户
        WrkInfoStoreVO infoStore = infoDetail.getInfoStore();
        // 暂存 --> 工单信息
        WrkInfo tempStorageWrkInfo = BeanUtil.copyProperties(info, WrkInfo.class);
        // 暂存 商户信息
        WrkInfoStoreRecord tempStorageStore = BeanUtil.copyProperties(info, WrkInfoStoreRecord.class);
        // 暂存 终端信息
        WrkInfoTerminalRecord tempStorageTerminalRecord = BeanUtil.copyProperties(info, WrkInfoTerminalRecord.class);
        // 终端 巡检信息
        WrkInfoTerminalInsRecord tempStorageTerminalInsRecord = BeanUtil.copyProperties(info, WrkInfoTerminalInsRecord.class);
        // geo
        tempStorageTerminalInsRecord.setWorkLocation(info.getGeographicLocation());
        tempStorageTerminalInsRecord.setWorkAddress(info.getLocationAddress());

        tempStorageWrkInfo.setWrkId(wrkInfo.getWrkId());
        tempStorageStore.setWrkId(wrkInfo.getWrkId());
        tempStorageTerminalRecord.setWrkId(wrkInfo.getWrkId());
        tempStorageTerminalInsRecord.setWrkId(wrkInfo.getWrkId());
        LocalDateTime now = LocalDateTime.now();
        // 工单状态比较 -- 7应该是暂存
        if (info.getWrkStatus() != 9) {
            tempStorageWrkInfo.setWrkStatus(info.getWrkStatus());
            tempStorageWrkInfo.setDisposeTime(now);
//            // 修改 工单信息
//            updateById(tempStorageWrkInfo);
//            // 修改 商户信息
//            wrkInfoStoreRecordService.updateById(tempStorageStore);
//            // 修改 终端信息
//            wrkInfoTerminalRecordService.updateById(tempStorageTerminalRecord);
//            // 修改 终端巡检信息
//            wrkInfoTerminalInsRecordService.updateById(tempStorageTerminalInsRecord);
//            // 有巡检单并且巡检单不为空时, 去提交巡检单信息
//            if (TaskConfigUtils.isisInspection(info.getTaskId()) && CollUtil.isNotEmpty(info.getInspections())) {
//                inspectionDataService.submit(info);
//            }
//            return;
        }

        // 无需审核, 此处改变下 终端以及对应的商户信息
        if (reviewMethod == 1) {
            // 无需审核, 工单状态直接变为8
            tempStorageWrkInfo.setWrkStatus(8);

            // 此处应当修改 商户记录表
//            // 1. 修改工单
            Assert.notNull(wrkInfo, "请确认此工单是否存在");
            Store store = BeanUtil.copyProperties(info, Store.class);
            store.setStoreId(infoStore.getStoreId());
            Long terminalId = infoTerminal.getTerminalId();
            Terminal terminal = BeanUtil.copyProperties(info, Terminal.class);
            TerminalIns terminalIns = terminalInsService.getById(terminalId);
            // 终端附加信息 不为空
            AssertUtil.invalidate(ObjectUtil.isEmpty(terminalIns), "终端获取为空");
            // 拷贝复制 一些 提交的终端信息
            BeanUtil.copyProperties(info, terminalIns);
            terminal.setTerminalId(terminalId);
            // 解除终端占用
            terminal.setOccupy(0);
            terminalIns.setTerminalId(terminalId);
            // 设置 巡检时间为当前
            terminalIns.setInspectionTime(now);
            // 设置终端状态为 已巡检
            terminal.setTerminalStatus(1);
            // 本次巡检结果, 取字典表数据
            terminalIns.setServiceResult(info.getServiceResult());
            // 设置 审核通过次数 + 1
            Integer timesPass = terminalIns.getTimesPass();
            terminalIns.setTimesPass(timesPass == null ? 1 : timesPass + 1);
            // 修改 终端的状态
            getMerState(info.getTerminalStatus(), info.getStoreStatus(), info.getWorkType(), info.getServiceResult(), terminal, store);

            tempStorageStore.setState(store.getState());
            tempStorageTerminalInsRecord.setTimesPass(terminalIns.getTimesPass());
            tempStorageTerminalInsRecord.setInspectionStatus(terminal.getTerminalStatus());
            tempStorageTerminalInsRecord.setInspectionTime(now);

            // 这块 可能为新增商户以及终端信息
            // 更新商户 信息, 同时 也需要更新
            // 更新商户状态
            storeService.saveOrUpdate(store);
            // 更新终端状态
            terminalService.saveOrUpdate(terminal);
            // 更新终端巡检时间以及审核通过次数等
            terminalInsService.saveOrUpdate(terminalIns);
            // 还需要 更改 记录表对应的数据.
        }
        // 此时的 审核工单状态应当为待初审
        tempStorageWrkInfo.setWrkStatus(2);
        // 偏差
        Long deviation = StrUtil.isNotEmpty(tempStorageTerminalInsRecord.getGeographicLocation())
                ? distance(tempStorageTerminalInsRecord.getGeographicLocation(), tempStorageTerminalInsRecord.getWorkLocation()) : null;
        // 偏差（直线距离 米）
        tempStorageTerminalInsRecord.setDeviation(deviation);

        updateById(tempStorageWrkInfo);
        // 修改 商户信息
        wrkInfoStoreRecordService.updateById(tempStorageStore);
        // 修改 终端信息
        wrkInfoTerminalRecordService.updateById(tempStorageTerminalRecord);
        // 修改 终端对应巡检信息
        wrkInfoTerminalInsRecordService.updateById(tempStorageTerminalInsRecord);
        if (TaskConfigUtils.isisInspection(info.getTaskId()) && CollUtil.isNotEmpty(info.getInspections())) {
            inspectionDataService.submit(info);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdraw(List<Long> ids) {
        List<Integer> status = ListUtil.toList(1, 5, 6, 9);
        LambdaQueryWrapper<WrkInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(WrkInfo::getWrkId, ids);
        queryWrapper.in(WrkInfo::getWrkStatus, status);
        List<WrkInfo> list = list(queryWrapper);
        Assert.notEmpty(list, "请确认此工单是否存在或已经审核成功了");
        List<Long> wrkIds = list.stream().map(WrkInfo::getWrkId).collect(Collectors.toList());
        removeBatchByIds(wrkIds);
        wrkImgService.remove(new LambdaQueryWrapper<WrkImg>().in(WrkImg::getWrkId, wrkIds));
        inspectionDataService.remove(new LambdaQueryWrapper<InspectionData>().in(InspectionData::getInsId, wrkIds));
        // todo 终端占用状态和江西内蒙古
        wrkInfoStoreRecordService.removeBatchByIds(wrkIds);
        // 修改 终端信息
        wrkInfoTerminalRecordService.removeBatchByIds(wrkIds);
        // 修改 终端对应巡检信息
        wrkInfoTerminalInsRecordService.removeBatchByIds(wrkIds);

        // todo 解除终端的占用
        // todo 江苏工行, 建行内蒙古的撤回


    }

    /**
     * 工单审核
     *
     * @param audit 审核所需
     *              工单共计有7个状态,
     *              1. 已分配
     *              2. 审核中
     *              3. 初审通过-待复审
     *              4. 复审通过
     *              5. 初审驳回
     *              6. 复审驳回
     *              7. 初审通过
     *              8. 默认审核通过
     *                                        todo 当任务为只需要初审时, 点击初审通过, 则其状态由2 变为 7
     *                                        todo 当任务需要复审时, 点击初审通过, 其状态由2 变为3
     *                                        当任务不需要审核时, 点击提交, 工单状态, 由1 变为8
     */
    @Override
    public void audit(AuditDTO audit) {
        Integer auditStatus = audit.getAuditStatus();
        // 1== auditStatus 代表审核通过, 否则代表审核拒绝
        // 获取工单信息
        WrkInfo wrkInfo = getById(audit.getWrkId());
        AssertUtil.invalidate(ObjectUtil.isEmpty(wrkInfo), "未找寻到对应工单");
        // 审核方式
        Integer reviewMethod = TaskConfigUtils.reviewMethod(wrkInfo.getTaskId());
        // 工单状态(记录表使用) 1. 已分配 2. 审核中 3. 初审通过-待复审 4. 复审通过 5. 初审驳回 6. 复审驳回 7. 初审通过 8. 默认审核通过
        // 当前 任务审核方式为 无需审核
        AssertUtil.invalidate(1 == reviewMethod, "当前工单所属任务为无需审核");
        Integer curStatus = wrkInfo.getWrkStatus();
        WrkInfo auditInfo = new WrkInfo();
        auditInfo.setWrkId(audit.getWrkId());
        // 不为
        AssertUtil.invalidate(2 != curStatus && 3 != curStatus, "当前工单状态不属于待审核状态");
        // 说明在审核中
        if (2 == curStatus) {
            // 只需要初审
            if (2 == reviewMethod) {
                // 通过或者驳回
                auditInfo.setWrkStatus(1 == auditStatus ? 7 : 5);
            }
            // 需要复审
            else if (3 == reviewMethod) {
                auditInfo.setWrkStatus(1 == auditStatus ? 3 : 5);
            }
        }
        // 不为待审核中时, 即为 3, 待复审 && 需要复审
        else if (3 == reviewMethod) {
            // 获取上一个审核
            List<WrkInfoAudit> list = infoAuditService.list(new LambdaQueryWrapper<WrkInfoAudit>()
                    .eq(WrkInfoAudit::getWrkId, audit.getWrkId())
                    // 此处需要的 初审通过-待复审 的记录信息
                    .eq(WrkInfoAudit::getAuditState, 3)
                    .eq(WrkInfoAudit::getIsRecord, 0)
            );
            AssertUtil.invalidate(CollectionUtil.isEmpty(list), "待复审工单, 未找寻到初审信息");
            for (WrkInfoAudit wrkInfoAudit : list) {
                AssertUtil.invalidate(wrkInfoAudit.getUserId().equals(SecurityUtils.getUserId()), "两次审核通过不能为同一人");
            }
            auditInfo.setWrkStatus(1 == auditStatus ? 4 : 6);
        }
        // 处理工单信息
        updateStateById(auditInfo);
        // 审核记录
        saveAndUpdateAudit(audit, auditInfo.getWrkStatus());
    }

    /**
     * 新增一条审核记录
     */
    private void saveAndUpdateAudit(AuditDTO audit, int wrkStatus) {
        // 新增一条审核工单记录
        WrkInfoAudit infoAudit = new WrkInfoAudit();
        infoAudit.setIsRecord(1);
        // 修改其他记录为历史
        infoAuditService.update(
                infoAudit,
                new LambdaQueryWrapper<WrkInfoAudit>()
                        .eq(WrkInfoAudit::getWrkId, audit.getWrkId())
        );
        // 同时新增一条记录
        infoAudit.setAuditState(wrkStatus);
        infoAudit.setAuditTime(LocalDateTime.now());
        infoAudit.setUserId(SecurityUtils.getUserId());
        infoAudit.setUserName(SecurityUtils.getUsername());
        infoAudit.setWrkId(audit.getWrkId());
        infoAudit.setDeptId(SecurityUtils.getDeptId());
        infoAudit.setIsRecord(0);
        infoAudit.setRemark(audit.getRemark());
        // 此处需要创建一条审核记录
        infoAuditService.save(infoAudit);
    }

    private void updateStateById(WrkInfo auditWrkInfo) {
        // 3,7  代表初审通过 4, 代表复审通过
        Integer wrkStatus = auditWrkInfo.getWrkStatus();
        // 修改 工单的审核状态
        updateById(auditWrkInfo);
        // 解除 终端占用, 因为审核通过了
        if (4 == wrkStatus || 7 == wrkStatus) {
            // 工单, 商户, 终端信息
            WrkInfoDetailsVO infoDetail = baseMapper.getWrkInfoDetails(auditWrkInfo.getWrkId());
            // 工单
            WrkInfoVO wrkInfo = infoDetail.getWrkInfo();
            // 终端
            WrkInfoTerminalVO infoTerminal = infoDetail.getInfoTerminal();
            // 商户
            WrkInfoStoreVO infoStore = infoDetail.getInfoStore();
            // 终端巡检
            WrkInfoTerminalInsVO infoTerminalIns = infoDetail.getInfoTerminalIns();
            LocalDateTime now = LocalDateTime.now();
            // 此处应当修改 商户记录表
//            // 1. 修改工单
            Assert.notNull(wrkInfo, "请确认此工单是否存在");
            Store store = BeanUtil.copyProperties(infoStore, Store.class);
            store.setStoreId(infoStore.getStoreId());

            Terminal terminal = BeanUtil.copyProperties(infoTerminal, Terminal.class);
            Long terminalId = infoTerminal.getTerminalId();
            // 拷贝复制 一些 提交的终端信息
            terminal.setTerminalId(terminalId);
            // 解除终端占用
            terminal.setOccupy(0);
            // 设置终端状态为 已巡检
            terminal.setTerminalStatus(1);

            TerminalIns terminalIns = BeanUtil.copyProperties(infoTerminalIns, TerminalIns.class);
            terminalIns.setTerminalId(terminal.getTerminalId());
            terminalIns.setTerminalId(terminalId);
            // 设置 巡检时间为当前
            terminalIns.setInspectionTime(now);
            // 本次巡检结果, 取字典表数据
            terminalIns.setServiceResult(wrkInfo.getServiceResult());
            // 设置 审核通过次数 + 1
            Integer timesPass = terminalIns.getTimesPass();
            terminalIns.setTimesPass(timesPass == null ? 1 : timesPass + 1);
            // 修改 终端的状态
            getMerState(infoTerminal.getTerminalStatus(),
                    infoStore.getStoreStatus(),
                    wrkInfo.getWorkType(),
                    wrkInfo.getServiceResult(),
                    terminal, store);
            store.setState(store.getState());
            terminalIns.setInspectionStatus(1);
            // 更新对应的终端以及商户信息
            // 这块 可能为新增商户以及终端信息
            // 更新商户 信息, 同时 也需要更新
            // 更新商户状态
            storeService.saveOrUpdate(store);
            // 更新终端状态
            terminalService.saveOrUpdate(terminal);
            // 更新终端巡检时间以及审核通过次数等
            terminalInsService.saveOrUpdate(terminalIns);
            // 还需要 更改 记录表对应的数据.

            if (enable) {
                // 江苏工行的数据推送
                PoolUtils.SENTINEL.getInstance().execute(() -> {
                    // 只有江苏工行的才进行推送
                    if (wrkInfo.getTaskId().equals(1701151817643495425L) && WorkTypeOperation.workTypes().contains(wrkInfo.getWorkType())) {
                        SpringUtils.getBean(WrkIcbcJsService.class).push(infoDetail);
                    }
                });
            }
        }
        // 需要同步修改 商户信息 以及 终端信息
    }


    @Override
    @Transactional
    public Long dispatch(WrkInfo wrkInfo, Store store, Terminal terminal, TerminalIns terminalIns) {
        // 工单信息
        save(wrkInfo);
        //终端信息
        WrkInfoTerminalRecord wrkInfoTerminalRecord = BeanUtil.copyProperties(terminal, WrkInfoTerminalRecord.class);
        wrkInfoTerminalRecord.setWrkId(wrkInfo.getWrkId());
        wrkInfoTerminalRecordService.save(wrkInfoTerminalRecord);
        // 终端巡检信息
        WrkInfoTerminalInsRecord wrkInfoTerminalInsRecord = BeanUtil.copyProperties(terminalIns, WrkInfoTerminalInsRecord.class);
        wrkInfoTerminalInsRecord.setWrkId(wrkInfo.getWrkId());
        wrkInfoTerminalInsRecordService.save(wrkInfoTerminalInsRecord);
        // 商户信息
        WrkInfoStoreRecord wrkInfoStoreRecord = BeanUtil.copyProperties(store, WrkInfoStoreRecord.class);
        wrkInfoStoreRecord.setWrkId(wrkInfo.getWrkId());
        wrkInfoStoreRecord.setDeptId(wrkInfo.getDeptId());
        wrkInfoStoreRecord.setStoreId(store.getStoreId());
        wrkInfoStoreRecordService.save(wrkInfoStoreRecord);
        return wrkInfo.getWrkId();
    }

    @Override
    public List<CountVO> countByProjectIds(Set<Long> projectIds, Set<Integer> wrkType) {
        return baseMapper.countByProjectIds(projectIds, wrkType);
    }

    /**
     * 计算经纬度 偏差
     */
    private Long distance(String origins, String destination) {
        HashMap<String, Object> map = new HashMap<>() {{
            put("origins", origins);
            put("destination", destination);
            put("type", 0);
            put("output", "JSON");
            put("key", "630449710597f6cdb7b6210fc1ab1063");
        }};

        try {
            String value = HttpUtil.get("https://restapi.amap.com/v3/distance", map);
            JSONObject jsonObject = JSONUtil.parseObj(value);
            JSONArray results = jsonObject.getJSONArray("results");
            if (jsonObject.getInt("status") == 1 && results != null && !results.isEmpty()) {
                return JSONUtil.parseObj(results.get(0)).getLong("distance");
            } else if ("DAILY_QUERY_OVER_LIMIT".equals(jsonObject.getStr("info"))) {
                return (long) -2;
            }
        } catch (Exception e) {
            log.error("获取位置信息失败");
        }
        return (long) -1;
    }

    /**
     * 获取商户状态
     */
    private void getMerState(Integer terminalStatus,
                             Integer storeStatus,
                             Integer workType,
                             Integer serviceResult,
                             Terminal record, Store store) {

        // 2023年4月19号修改 ： 市场部
        //撤机 两种情况下归属撤机

        //异常  四种情况归为异常
        // 不管是撤机还是异常 只有在审核通过之后才改变状态
        // 审核拒绝之后 撤回 回归原来状态

        // 撤机  1 机具状态 选择 银行撤机 2 工单类型选择 撤机
        if (DictUtils.getDictLabel("terminal_status", "银行撤机").equals(String.valueOf(terminalStatus)) ||
                DictUtils.getDictLabel("wrk_type", "撤机").equals(String.valueOf(workType))) {
            //设置商户状态为异常
            store.setState(Integer.valueOf(Objects.requireNonNull(DictUtils.getDictValue("mer_status", "异常"))));
            // 添加备注
            // 终端状态
            // 终端状态改为 已经撤机, 此处可能会改为 异常
            record.setTerminalStatus(Integer.valueOf(DictUtils.getDictLabel("terminal_status", "银行撤机")));
            record.setRemark(DictUtils.getDictLabel("terminal_status", String.valueOf(terminalStatus)));

        }
        // 异常  服务结果 选择  原址无此终端 和 原址无此商户 机具状态 选择 设备丢失 门店状态 选择  门店不存在
        else if (DictUtils.getDictLabel("terminal_status", "设备丢失").equals(String.valueOf(terminalStatus)) ||
//                门店状态
                DictUtils.getDictLabel("store_status", "门店不存在").equals(String.valueOf(storeStatus)) ||
                // service_results 服务结果
                List.of(DictUtils.getDictLabel("service_results", "原址无此终端"), DictUtils.getDictLabel("service_results", "原址无此商户"))
                        .contains(String.valueOf(serviceResult))) {
            // 设置商户状态为异常
            //设置商户状态为异常
            store.setState(Integer.valueOf(Objects.requireNonNull(DictUtils.getDictValue("mer_status", "异常"))));
            record.setRemark(DictUtils.getDictLabel("terminal_status", String.valueOf(terminalStatus)));
        } else {
            // 商户正常
            store.setState(Integer.valueOf(Objects.requireNonNull(DictUtils.getDictValue("mer_status", "正常"))));
            // 终端正常
            record.setRemark(DictUtils.getDictLabel("terminal_status", String.valueOf(terminalStatus)));
        }
    }

    /**
     * 此处调用后台执行 -- 下载word 工单
     */
    public Result<String> downInspectionTemplate(String params) {
        ReviewedQuery query = JSON.parseObject(params, ReviewedQuery.class);
        // 先查询是否存在对应的记录
        WrapperUtils.buildSql(query);
        // 需要导出 工单信息
        List<WrkInfoDetailsVO> wrkInfoDetailsVOS = baseMapper.listInsTemplate(query);
        if (CollectionUtil.isEmpty(wrkInfoDetailsVOS)) {
            return Result.failed("查询工单为空");
        }
        // 工单map
        Map<Long, WrkInfoDetailsVO> wrkMap =
                wrkInfoDetailsVOS.stream().collect(Collectors.toMap(w -> w.getWrkInfo().getWrkId(), o -> o));
        // 工单图片
        List<WrkImgVO> imgList = wrkImgService.listImgByWrkIds(wrkMap.keySet());
        Map<Long, List<WrkImgVO>> imgMap = imgList.stream().collect(Collectors.groupingBy(WrkImgVO::getWrkId));
        List<InspectionConfigVO> insConfigs = inspectionDataService.listInspections(wrkMap.keySet());
        Map<Long, List<InspectionConfigVO>> configMap = insConfigs.stream().collect(Collectors.groupingBy(InspectionConfigVO::getWrkId));
        wrkMap.forEach((wrkId, infoDetail) -> {
            List<WrkImgVO> wrkImgs = imgMap.get(wrkId);
            infoDetail.setInfoImg(wrkImgs);
            List<InspectionConfigVO> inspectionConfigVOS = configMap.get(wrkId);
            infoDetail.setInspections(inspectionConfigVOS);
        });
        // 此处 去调用 生成 word 文档
        return Result.ok(generatedInsFactory.generated(wrkMap));
    }
}
