package com.skr.mdm.api.app.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.github.pagehelper.PageHelper;
import com.skr.mdm.api.app.service.AppStrategyInfoService;
import com.skr.mdm.api.app.service.AppStrategyService;
import com.skr.mdm.api.template.AbstractDefaultStrategyService;
import com.skr.mdm.bean.qo.BaseQueryQO;
import com.skr.mdm.bean.qo.BaseStrategyQO;
import com.skr.mdm.bean.qo.app.AppStrategyQO;
import com.skr.mdm.bean.so.app.AppStrategySO;
import com.skr.mdm.bean.vo.app.AppStrategyInfoVO;
import com.skr.mdm.bean.vo.strategy.StrategyUserVO;
import com.skr.mdm.dao.AppStrategyDao;
import com.skr.mdm.dao.AppStrategyUserDao;
import com.skr.mdm.dao.DeviceEquipmentDao;
import com.skr.mdm.dto.LoginAdminDTO;
import com.skr.mdm.entity.AppStrategyDO;
import com.skr.mdm.entity.AppStrategyUserDO;
import com.skr.mdm.enums.*;
import com.skr.mdm.handle.IssuedUserHandler;
import com.skr.mdm.handle.LogAdminHandler;
import com.skr.mdm.manager.AppStrategyManager;
import com.skr.mdm.result.ResponseResult;
import com.skr.mdm.util.MdmListUtil;
import com.skr.mdm.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author nfq
 * @date 2022-10-24 13:55
 */
@Service
@Slf4j
public class AppStrategyServiceImpl extends AbstractDefaultStrategyService implements AppStrategyService {

    private final String MODULE = "应用策略";

    private AppStrategyQO appStrategyQO;

    @Autowired
    private AppStrategyDao appStrategyDao;
    @Autowired
    private AppStrategyUserDao appStrategyUserDao;
    @Autowired
    private LogAdminHandler logAdminHandler;
    @Autowired
    private IssuedUserHandler issuedUserHandler;
    @Autowired
    private DeviceEquipmentDao equipmentDao;
    @Autowired
    private AppStrategyManager appStrategyManager;
    @Autowired
    private List<AppStrategyInfoService> appStrategyInfoServiceList;

    @Override
    protected Object getStrategyInfo(Integer strategyId) {
        AppStrategyInfoVO appStrategyInfoVO = new AppStrategyInfoVO();
        AppStrategyDO appStrategyDO = appStrategyDao.selectById(strategyId);
        BeanUtils.copyProperties(appStrategyDO, appStrategyInfoVO);
        appStrategyInfoServiceList.forEach(appStrategyInfoService ->
                appStrategyInfoService.setAppStrategyInfoVO(appStrategyInfoVO, strategyId));
        return appStrategyInfoVO;
    }

    @Override
    protected long strategyStateCheck(List<Integer> strategyIdList) {
        return 0;
    }

    @Override
    protected void updateStrategyIssuedState(List<Integer> strategyIdList, BaseStrategyQO baseStrategyQO) {
        new LambdaUpdateChainWrapper<>(appStrategyDao)
                .set(AppStrategyDO::getState, baseStrategyQO.getState())
                .in(AppStrategyDO::getId, strategyIdList)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStrategyDeptGlobal(List<Integer> strategyIdList, List<Integer> departmentIdList) {
        new LambdaUpdateChainWrapper<>(appStrategyDao)
                .set(AppStrategyDO::getDepartmentIds, JSONUtil.toJsonStr(departmentIdList))
                .in(AppStrategyDO::getId, strategyIdList)
                .update();
    }

    @Override
    protected List<Integer> getEquipmentIdListByStrategyIdList(List<Integer> strategyIdList) {
        return appStrategyUserDao.listEquipmentIdByStrategyIds(strategyIdList);
    }

    @Override
    protected List<Integer> getEquipmentIdListByStrategyIdListForDeptGlobal(List<Integer> strategyIdList) {
        List<AppStrategyDO> appStrategyDOList = appStrategyDao.selectBatchIds(strategyIdList);
        if (CollectionUtils.isNotEmpty(appStrategyDOList) && StringUtils.isNotBlank(appStrategyDOList.get(0).getDepartmentIds())) {
            List<Integer> departmentIdList = JSONUtil.toList(JSONUtil.parseArray(appStrategyDOList.get(0).getDepartmentIds()), Integer.class);
            if (CollectionUtils.isNotEmpty(departmentIdList)) {
                return equipmentDao.listEquipmentIdByDepartmentIdList(departmentIdList);
            }
        }
        return Collections.emptyList();
    }

    @Override
    protected void adminLogIssuedStrategy(List<Integer> strategyIdList, BaseStrategyQO baseStrategyQO, LoginAdminDTO loginAdminDTO) {
        String content = "";
        List<AppStrategyDO> appStrategyDOList = appStrategyDao.selectBatchIds(strategyIdList);
        if (CollectionUtils.isNotEmpty(appStrategyDOList)) {
            List<String> strategyNameList = appStrategyDOList.stream().map(AppStrategyDO::getStrategyName).collect(Collectors.toList());
            content = "下发应用策略 策略名：" + StringUtils.join(strategyNameList, "，");
        }
        logAdminHandler.log(baseStrategyQO, loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), content, MODULE);
    }

    @Override
    public void saveStrategyUser(List<Integer> strategyIdList, List<Integer> equipmentIdList, LoginAdminDTO loginAdminDTO) {
        Date date = new Date();
        strategyIdList.forEach(strategyId -> {
            List<Integer> listEquipmentIdByStrategyIds = appStrategyUserDao.listEquipmentIdByStrategyIds(ListUtil.toList(strategyId));
            List<Integer> addEquipmentIdList = MdmListUtil.difference(equipmentIdList, listEquipmentIdByStrategyIds);
            List<Integer> updateEquipmentIdList = MdmListUtil.intersection(equipmentIdList, listEquipmentIdByStrategyIds);
            // 新增
            if (CollectionUtils.isNotEmpty(addEquipmentIdList)) {
                List<AppStrategyUserDO> appStrategyUserDOList = new ArrayList<>(addEquipmentIdList.size());
                addEquipmentIdList.forEach(equipmentId -> {
                    AppStrategyUserDO appStrategyUserDO = AppStrategyUserDO.builder()
                            .equipmentId(equipmentId)
                            .strategyId(strategyId)
                            .state(StrategyEquipmentStateEnum.ISSUING.getState())
                            .issuedTime(date)
                            .build();
                    appStrategyUserDOList.add(appStrategyUserDO);
                });
                appStrategyUserDao.insertBatch(appStrategyUserDOList);
            }
            // 更新
            if (CollectionUtils.isNotEmpty(updateEquipmentIdList)) {
                new LambdaUpdateChainWrapper<>(appStrategyUserDao)
                        .set(AppStrategyUserDO::getState, StrategyEquipmentStateEnum.ISSUING.getState())
                        .set(AppStrategyUserDO::getIssuedTime, date)
                        .eq(AppStrategyUserDO::getStrategyId, strategyId)
                        .in(AppStrategyUserDO::getEquipmentId, updateEquipmentIdList)
                        .update();
            }
        });
    }

    @Override
    public void doIssuedStrategy(List<Integer> strategyIdList, List<Integer> equipmentIdList, LoginAdminDTO loginAdminDTO) {
        List<AppStrategySO> appStrategySOList = appStrategyManager.getAppStrategySOList(strategyIdList);
        if (CollectionUtils.isNotEmpty(appStrategySOList)) {
            issuedUserHandler.issuedUser(equipmentIdList, loginAdminDTO.getCompanyId(),
                    SendCmdConfigEnum.APP_STRATEGY_ISSUED.getCmd(), JSONUtil.toJsonStr(appStrategySOList));
        }
    }

    @Override
    protected long checkDuplicateStrategy(Object operationObject, LoginAdminDTO loginAdminDTO) {
        this.appStrategyQO = (AppStrategyQO) operationObject;
        return new LambdaQueryChainWrapper<>(appStrategyDao)
                .eq(AppStrategyDO::getStrategyName, appStrategyQO.getStrategyName())
                .eq(AppStrategyDO::getCompanyId, loginAdminDTO.getCompanyId())
                .ne(appStrategyQO.getId() != null, AppStrategyDO::getId, appStrategyQO.getId())
                .count();
    }

    @Override
    protected Integer saveStrategy(Object operationObject, LoginAdminDTO loginAdminDTO) {
        AppStrategyDO strategyDO = AppStrategyDO.builder()
                .companyId(loginAdminDTO.getCompanyId())
                .state(StrategyStateEnum.SAVE.getState())
                .operator(loginAdminDTO.getAdminName())
                .operateTime(new Date())
                .departmentIds("")
                .build();
        BeanUtils.copyProperties(appStrategyQO, strategyDO);
        if (IssuedTypeEnum.DEPT_GLOBAL.getIssuedType().equals(appStrategyQO.getGlobalType()) &&
                CollectionUtils.isNotEmpty(appStrategyQO.getCandidateIdList())) {
            strategyDO.setDepartmentIds(JSONUtil.toJsonStr(appStrategyQO.getCandidateIdList()));
        }
        appStrategyDao.insert(strategyDO);
        // 保存应用策略信息子策略
        appStrategyInfoServiceList.forEach(appStrategyInfoService -> appStrategyInfoService.saveAppStrategy(appStrategyQO,
                strategyDO.getId()));
        return strategyDO.getId();
    }

    @Override
    protected void adminLogAddStrategy(LoginAdminDTO loginAdminDTO) {
        String logContent = "应用策略 策略名：" + appStrategyQO.getStrategyName();
        if (appStrategyQO.getId() == null) {
            logContent = "创建" + logContent;
        } else {
            logContent = "编辑" + logContent;
        }
        logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), logContent, MODULE, Collections.emptyList());
    }

    @Override
    protected Integer updateStrategyById(Object operationObject, LoginAdminDTO loginAdminDTO) {
        AppStrategyDO strategyDO = AppStrategyDO.builder()
                .operator(loginAdminDTO.getAdminName())
                .operateTime(new Date())
                .build();
        BeanUtils.copyProperties(appStrategyQO, strategyDO);
        if (IssuedTypeEnum.DEPT_GLOBAL.getIssuedType().equals(appStrategyQO.getGlobalType()) &&
                CollectionUtils.isNotEmpty(appStrategyQO.getCandidateIdList())) {
            strategyDO.setDepartmentIds(JSONUtil.toJsonStr(appStrategyQO.getCandidateIdList()));
        }
        appStrategyDao.updateById(strategyDO);
        // 删除并保存
        appStrategyInfoServiceList.forEach(appStrategyInfoService ->
                appStrategyInfoService.deleteAppStrategy(Collections.singletonList(strategyDO.getId())));
        // 保存应用策略信息子策略
        appStrategyInfoServiceList.forEach(appStrategyInfoService ->
                appStrategyInfoService.saveAppStrategy(appStrategyQO, strategyDO.getId()));
        return strategyDO.getId();
    }

    @Override
    protected void issuedStrategyDelete(List<Integer> strategyIdList, LoginAdminDTO loginAdminDTO) {
        List<Integer> listEquipmentIdByStrategyIds = appStrategyUserDao.listEquipmentIdByStrategyIds(strategyIdList);
        issuedUserHandler.issuedUser(listEquipmentIdByStrategyIds, loginAdminDTO.getCompanyId(),
                SendCmdConfigEnum.APP_STRATEGY_DELETE.getCmd(), JSONUtil.toJsonStr(strategyIdList));
    }

    @Override
    protected void doDeleteStrategy(List<Integer> strategyIdList) {
        appStrategyInfoServiceList.forEach(appStrategyInfoService -> appStrategyInfoService.deleteAppStrategy(strategyIdList));
        appStrategyUserDao.delete(Wrappers.lambdaQuery(AppStrategyUserDO.class)
                .in(AppStrategyUserDO::getStrategyId, strategyIdList));
        appStrategyDao.deleteBatchIds(strategyIdList);
    }

    @Override
    protected void adminLogDeleteStrategy(List<Integer> strategyIdList, LoginAdminDTO loginAdminDTO) {
        strategyIdList.forEach(strategyId -> {
            AppStrategyDO appStrategyDO = appStrategyDao.selectById(strategyId);
            List<Integer> listEquipmentIdByStrategyIds = appStrategyUserDao.listEquipmentIdByStrategyIds(Collections.singletonList(strategyId));
            String content = "删除应用策略 策略名：" + appStrategyDO.getStrategyName();
            logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), content, MODULE, listEquipmentIdByStrategyIds);
        });
    }

    @Override
    protected void doUpdateStrategyState(Integer strategyId, Integer state, LoginAdminDTO loginAdminDTO) {

    }

    @Override
    protected BaseStrategyQO createBaseStrategyQO(Integer strategyId) {
        return null;
    }

    @Override
    protected void adminLogUpdateStrategyState(Integer strategyId, Integer state, List<Integer> equipmentIdList, LoginAdminDTO loginAdminDTO) {

    }

    @Override
    protected void issuedStrategyState(Integer strategyId, Integer state, List<Integer> equipmentIdList, LoginAdminDTO loginAdminDTO) {

    }

    @Override
    protected List<StrategyUserVO> getStrategyUserList(Integer strategyId, Integer searchType, String searchValue) {
        return appStrategyUserDao.listStrategyUser(strategyId, searchType, searchValue);
    }

    @Override
    protected void issuedStrategyUserDelete(Integer strategyId, List<Integer> equipmentIdList, LoginAdminDTO loginAdminDTO) {
        issuedUserHandler.issuedUser(equipmentIdList, loginAdminDTO.getCompanyId(),
                SendCmdConfigEnum.APP_STRATEGY_DELETE.getCmd(), JSONUtil.toJsonStr(ListUtil.toList(strategyId)));
    }

    @Override
    protected void doDeleteStrategyUser(Integer strategyId, List<Integer> equipmentIdList) {
        appStrategyUserDao.delete(
                Wrappers.lambdaQuery(AppStrategyUserDO.class)
                        .eq(AppStrategyUserDO::getStrategyId, strategyId)
                        .in(AppStrategyUserDO::getEquipmentId, equipmentIdList));
    }

    @Override
    protected void adminLogDeleteStrategyUser(Integer strategyId, List<Integer> equipmentIdList, LoginAdminDTO loginAdminDTO) {
        AppStrategyDO strategyDO = appStrategyDao.selectById(strategyId);
        if (strategyDO == null) {
            log.warn("strategyDO 不应该为null");
            return;
        }
        String content = "应用策略作用人删除 策略名：" + strategyDO.getStrategyName();
        logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), content, MODULE, equipmentIdList);
    }

    @Override
    public ResponseResult listStrategy(BaseQueryQO baseQueryQO, LoginAdminDTO loginAdminDTO) {
        List<Integer> strategyIdList = null;
        if (baseQueryQO.getSearchType() != null && baseQueryQO.getSearchType().equals(2)) {
            strategyIdList = appStrategyDao.listStrategyIdByStrategyContent(baseQueryQO.getSearchValue());
        }
        PageHelper.startPage(baseQueryQO.getPageNum(), baseQueryQO.getPageSize());
        return ResponseResult.success(PageUtil.getPageResult(appStrategyDao.listAppStrategyVO(loginAdminDTO.getCompanyId(),
                strategyIdList, baseQueryQO.getSearchType(), baseQueryQO.getSearchValue())));
    }
}