package com.tuoheng.admin.service.inspection.delete;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.entity.InspectionFile;
import com.tuoheng.admin.entity.User;
import com.tuoheng.admin.enums.InspectionStatusEnum;
import com.tuoheng.admin.enums.DataPermissionEnum;
import com.tuoheng.admin.enums.MarkEnum;
import com.tuoheng.admin.enums.code.inspection.DeleteInspectionCodeEnum;
import com.tuoheng.admin.mapper.*;
import com.tuoheng.admin.utils.CurrentUserUtil;
import com.tuoheng.common.core.utils.DateUtils;
import com.tuoheng.common.core.utils.JsonResult;
import com.tuoheng.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 删除任务业务层处理
 *
 * @author wanjing
 * @team tuoheng
 * @date 2022-11-24
 */
@Slf4j
@Service
public class DeleteInspectionService {

    @Autowired
    private InspectionMapper inspectionMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private InspectionFileMapper inspectionFileMapper;

    @Autowired
    private InspectionFileHandleMapper inspectionFileHandleMapper;

    @Autowired
    private InspectionHistoryMapper inspectionHistoryMapper;

    /**
     * 删除任务业务
     * 1）、对入参判断
     * 2）、对任务状态判断，处于飞行中的任务无法删除
     * 3）、对用户权限判断，超级管理员可删除任何任务；管理员能删除本部门任务，不能删除子部门任务；普通用户不能删除任务
     * 4）、删除任务、任务问题、任务处理数据
     * 4.1）、已完成的任务，进行逻辑删除
     * 4.2）、待飞行任务、失败状态的任务，进行物理删除
     *
     * @param id
     * @return
     */
    @Transactional
    public JsonResult deleteById(String id) {
        log.info("进入删除任务业务接口");
        String userId = CurrentUserUtil.getUserId();
        String tenantId = CurrentUserUtil.getTenantId();
        JsonResult result = this.check(tenantId, id);
        if (0 != result.getCode()) {
            log.info("删除任务接口：校验失败：{}", result.getMsg());
            return result;
        }

        // 在校验中，判断任务是否存在时，若任务存在，直接将任务信息返回，减少数据库查询次数
        Inspection inspection = (Inspection) result.getData();

        // 判断任务状态，处于飞行中的任务无法删除
        result = this.checkStatus(inspection);
        if (0 != result.getCode()) {
            log.info("删除任务接口：任务处于飞行中时无法删除");
            return result;
        }

        // 判断是否有删除权限
        result = this.checkPermission(tenantId, userId, inspection);
        if (0 != result.getCode()) {
            log.info("删除任务接口：没有权限，{}", result.getMsg());
            return result;
        }

        // 设置该删除务的操作用户，时间
        inspection.setUpdateUser(userId);
        inspection.setUpdateTime(DateUtils.now());

        // 删除任务、任务问题、任务处理结果
        result = this.deleted(inspection);
        if (0 != result.getCode()) {
            log.info("删除任务业务接口：删除任务失败：{}", result.getMsg());
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }

        log.info("删除任务业务接口：删除任务成功：id={}", inspection.getId());
        return JsonResult.success("删除部门任务");
    }

    /**
     * 检查参数
     *
     * @param tenantId
     * @param id
     * @return
     */
    private JsonResult check(String tenantId, String id) {
        // 判断id是否为空
        if (StringUtils.isEmpty(id)) {
            return JsonResult.error(DeleteInspectionCodeEnum.ID_IS_NULL.getCode(), DeleteInspectionCodeEnum.ID_IS_NULL.getMsg());
        }

        // 判断任务是否存在
        Inspection inspection = inspectionMapper.selectOne(new LambdaQueryWrapper<Inspection>()
                .eq(Inspection::getTenantId, tenantId)
                .eq(Inspection::getId, id)
                .eq(Inspection::getMark, 1));
        if (null == inspection) {
            return JsonResult.error(DeleteInspectionCodeEnum.INSPECTION_IS_NOT_EXIST.getCode(), DeleteInspectionCodeEnum.INSPECTION_IS_NOT_EXIST.getMsg());
        }
        return JsonResult.success(inspection);
    }

    /**
     * 任务处于飞行中时无法删除
     *
     * @param inspection
     * @return
     */
    private JsonResult checkStatus(Inspection inspection) {
        if (InspectionStatusEnum.PREPARING.getCode() == inspection.getStatus() || InspectionStatusEnum.IN_FLIGHT.getCode() == inspection.getStatus()) {
            return JsonResult.error(DeleteInspectionCodeEnum.IN_FLIGHT_NOT_DELETE.getCode(), DeleteInspectionCodeEnum.IN_FLIGHT_NOT_DELETE.getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 判断是否有删除权限
     * 1）、超级管理员可以删除所有任务
     * 2）、管理员可删除本部门任务，无法删除子部门任务
     * 3）、普通用户无权限删除任务
     *
     * @param tenantId
     * @param userId
     * @param inspection
     * @return
     */
    private JsonResult checkPermission(String tenantId, String userId, Inspection inspection) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getTenantId, tenantId)
                .eq(User::getId, userId)
                .eq(User::getMark, MarkEnum.VALID.getCode()));
        if (DataPermissionEnum.ALL.getCode() == user.getDataPermission()) {
            return JsonResult.success();
        } else if (DataPermissionEnum.DEPT_AND_SUB_DEPT.getCode() == user.getDataPermission()) {
            if (user.getDeptId().equals(inspection.getDeptId())) {
                return JsonResult.success();
            }
            return JsonResult.error(DeleteInspectionCodeEnum.ADMIN_NOT_DELETE_CHILD_INSPECTION.getCode(), DeleteInspectionCodeEnum.ADMIN_NOT_DELETE_CHILD_INSPECTION.getMsg());
        } else if (DataPermissionEnum.DEPT.getCode() == user.getDataPermission()) {
            return JsonResult.error(DeleteInspectionCodeEnum.ORDINARY_USER_NO_PERMISSION_TO_DELETE.getCode(), DeleteInspectionCodeEnum.ORDINARY_USER_NO_PERMISSION_TO_DELETE.getMsg());
        }
        return JsonResult.error();
    }

    /**
     * 删除任务
     * 1）、已完成的任务被删除后任务历史信息保留在服务器中，不再展示
     * 2）、待飞行任务、失败状态的任务被删除后，任务不再执行，不保存任务信息到服务器中
     * 3)、此处删除根据 1，2中需求，涉及逻辑删除和物理删除，不同删除操作，对任务、任务问题、任务问题处理结果的关联删除也不一样
     * 4)、此方法，提前将任务问题、任务问题处理结果给取出，后面进行不同的处理业务
     *
     * @return
     */
    private JsonResult deleted(Inspection inspection) {
        List<InspectionFile> inspectionFileList = inspectionFileMapper.selectList(new LambdaQueryWrapper<InspectionFile>()
                .eq(InspectionFile::getInspectionId, inspection.getId())
                .eq(InspectionFile::getMark, 1));
        List<String> inspectionFileIdList = inspectionFileList.stream().map(o -> o.getId()).collect(Collectors.toList());
        if (InspectionStatusEnum.FLIGHT_COMPLETED.getCode() == inspection.getStatus()) {
            this.deleteByLogic(inspection, inspectionFileIdList);
        } else if (InspectionStatusEnum.WAIT_FLIGHT.getCode() == inspection.getStatus()) {
            this.deleteByPhysical(inspection, inspectionFileIdList);
        } else if (InspectionStatusEnum.FLIGHT_FAILED.getCode() == inspection.getStatus()) {
            this.deleteByPhysical(inspection, inspectionFileIdList);
        }
        return JsonResult.success();
    }

    /**
     * 逻辑删除已完成的任务，任务被删除后任务历史信息保留在服务器中，不再展示，做逻辑删除，mark置为0，不去真正删除
     *
     * @return
     */
    private JsonResult deleteByLogic(Inspection inspection, List<String> inspectionFileIdList) {
        inspection.setUpdateTime(DateUtils.now());
        inspection.setMark(0);
        Integer rowId = inspectionMapper.deleteByLogic(inspection);
        log.info("删除任务业务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务：逻辑删除任务失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }

        // 逻辑删除任务问题数据
        this.deleteInspectionFileByLogic(inspection);

        // 逻辑删除任务问题处理结果数据
        this.deleteInspectionFileHandleByLogic(inspection, inspectionFileIdList);

        // 逻辑删除任务历史记录
        this.deleteInspectionHistoryByLogic(inspection);

        return JsonResult.success();
    }

    /**
     * 逻辑删除已完成的任务问题，
     * 1）、已完成任务被删除后，同步任务问题也需要删除
     * 2）、任务问题信息保留在服务器中，不再展示，做逻辑删除，mark置为0，不去真正删除
     *
     * @return
     */
    private JsonResult deleteInspectionFileByLogic(Inspection inspection) {
        Map<String, Object> map = this.getInspectionMap(inspection);
        Integer rowId = inspectionFileMapper.deleteLogicByMap(map);
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：逻辑删除任务问题失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 逻辑删除已完成的任务问题，
     * 1）、已完成任务被删除后，同步任务问题也需要删除
     * 2）、任务问题信息保留在服务器中，不再展示，做逻辑删除，mark置为0，不去真正删除
     *
     * @return
     */
    private JsonResult deleteInspectionFileHandleByLogic(Inspection inspection, List<String> inspectionFileIdList) {
        if (CollectionUtil.isEmpty(inspectionFileIdList)) {
            return JsonResult.success();
        }
        Map<String, Object> map = this.getInspectionFileMap(inspection, inspectionFileIdList);
        Integer rowId = inspectionFileHandleMapper.deleteLogicByMap(map);
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：逻辑删除任务问题处理结果失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 逻辑删除任务历史记录
     * 1）、已完成任务被删除后，任务历史记录也需要删除
     * 2）、任务历史记录保留在服务器中，不再展示，做逻辑删除，mark置为0，不去真正删除
     *
     * @return
     */
    private JsonResult deleteInspectionHistoryByLogic(Inspection inspection) {
        Map<String, Object> map = this.getInspectionMap(inspection);
        Integer rowId = inspectionHistoryMapper.deleteLogicByMap(map);
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：逻辑删除任务历史记录失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 物理删除待飞行任务、失败状态的任务，删除后，任务不再执行，不保存任务信息到服务器中，做物理删除，真正删除
     *
     * @return
     */
    private JsonResult deleteByPhysical(Inspection inspection, List<String> inspectionFileIdList) {
        Integer rowId = inspectionMapper.deleteById(inspection.getId());
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：物理删除任务失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }

        // 物理删除任务问题数据
        this.deleteInspectionFileByPhysical(inspection);

        // 物理删除任务问题处理结果数据
        this.deleteInspectionFileHandleByPhysical(inspection, inspectionFileIdList);

        // 物理删除任务历史记录
        this.deleteInspectionHistoryByPhysical(inspection);

        return JsonResult.success();
    }

    /**
     * 物理删除已完成的任务问题，
     * 1）、已完成任务被删除后，同步任务问题也需要删除
     * 2）、物理删除
     *
     * @return
     */
    private JsonResult deleteInspectionFileByPhysical(Inspection inspection) {
        Integer rowId = inspectionFileMapper.deleteByInspectionId(inspection.getId());
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：逻辑删除任务问题失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 物理删除已完成的任务问题，
     * 1）、已完成任务被删除后，同步任务问题也需要删除
     * 2）、物理删除
     *
     * @return
     */
    private JsonResult deleteInspectionFileHandleByPhysical(Inspection inspection, List<String> inspectionFileIdList) {
        Integer rowId = inspectionFileHandleMapper.deleteByInspectionFileIdList(inspectionFileIdList);
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：逻辑删除任务问题处理结果失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 物理删除任务历史记录
     * 1）、已完成任务被删除后，同步任务问题也需要删除
     * 2）、物理删除
     *
     * @return
     */
    private JsonResult deleteInspectionHistoryByPhysical(Inspection inspection) {
        Integer rowId = inspectionHistoryMapper.deleteByInspectionId(inspection.getId());
        log.info("删除任务, 返回结果: rowId={}", rowId);
        if (rowId < 0) {
            log.info("删除任务业务接口：逻辑删除任务历史记录失败");
            return JsonResult.error(DeleteInspectionCodeEnum.DELETE_IS_FAILED.getCode(), DeleteInspectionCodeEnum.DELETE_IS_FAILED.getMsg());
        }
        return JsonResult.success();
    }

    private Map<String, Object> getInspectionMap(Inspection inspection) {
        Map<String, Object> map = new HashMap<>();
        map.put("mark", 0);
        map.put("updateUser", inspection.getUpdateUser());
        map.put("updateTime", DateUtils.now());
        map.put("inspectionId", inspection.getId());
        return map;
    }

    private Map<String, Object> getInspectionFileMap(Inspection inspection, List<String> inspectionFileIdList) {
        Map<String, Object> map = new HashMap<>();
        map.put("mark", 0);
        map.put("updateUser", inspection.getUpdateUser());
        map.put("updateTime", DateUtils.now());
        map.put("inspectionFileIdList", inspectionFileIdList);
        return map;
    }
}
