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

import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.skr.mdm.api.app.excel.AppConfigImportData;
import com.skr.mdm.api.app.excel.AppConfigImportDataListener;
import com.skr.mdm.api.app.service.AppConfigService;
import com.skr.mdm.api.app.service.AppStrategyInfoService;
import com.skr.mdm.bean.qo.BaseQueryQO;
import com.skr.mdm.bean.qo.app.AppConfigQO;
import com.skr.mdm.bean.so.app.AppConfigSO;
import com.skr.mdm.dao.AppConfigDao;
import com.skr.mdm.dao.DeviceEquipmentDao;
import com.skr.mdm.dto.LoginAdminDTO;
import com.skr.mdm.entity.AppConfigDO;
import com.skr.mdm.enums.AppConfigCmdEnum;
import com.skr.mdm.enums.LogAdminTypeEnum;
import com.skr.mdm.exception.ServiceException;
import com.skr.mdm.handle.IssuedUserHandler;
import com.skr.mdm.handle.LogAdminHandler;
import com.skr.mdm.result.ResponseResult;
import com.skr.mdm.util.PageUtil;
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.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author nfq
 * @date 2022-11-04 18:02
 */
@Service
public class AppConfigServiceImpl extends ServiceImpl<AppConfigDao, AppConfigDO> implements AppConfigService {

    private final String MODULE = "应用配置";

    @Autowired
    private LogAdminHandler logAdminHandler;
    @Autowired
    private List<AppStrategyInfoService> appStrategyInfoServiceList;
    @Autowired
    private IssuedUserHandler issuedUserHandler;
    @Autowired
    private DeviceEquipmentDao equipmentDao;


    @Override
    public ResponseResult list(BaseQueryQO baseQueryQO, LoginAdminDTO loginAdminDTO) {
        PageHelper.startPage(baseQueryQO.getPageNum(), baseQueryQO.getPageSize());
        return ResponseResult.success(PageUtil.getPageResult(baseMapper.listAppConfigVO(loginAdminDTO.getCompanyId(),
                baseQueryQO.getSearchType(), baseQueryQO.getSearchValue())));
    }

    @Override
    public ResponseResult add(List<AppConfigQO> appConfigQOList, LoginAdminDTO loginAdminDTO) {
        Set<String> appNameSet = appConfigQOList.stream().map(AppConfigQO::getAppName).collect(Collectors.toSet());
        // 检查数据重复
        checkAppConfigQOList(appConfigQOList);
        // 检查数据库数据重复
        for (AppConfigQO appConfigQO : appConfigQOList) {
            Long countPackageName = new LambdaQueryChainWrapper<>(baseMapper)
                    .eq(AppConfigDO::getCompanyId, loginAdminDTO.getCompanyId())
                    .eq(AppConfigDO::getPackageName, appConfigQO.getPackageName())
                    .eq(StringUtils.isNotBlank(appConfigQO.getAppSign()), AppConfigDO::getAppSign, appConfigQO.getAppSign())
                    .count();
            if (countPackageName > 0) {
                // 直接返回，不能抛异常否则导致应用发布添加出现问题
                return ResponseResult.failure("包名已存在");
            }
        }
        List<AppConfigDO> appConfigDOList = appConfigQOList.stream()
                .map(appConfigQO -> AppConfigDO.builder()
                        .companyId(loginAdminDTO.getCompanyId())
                        .operator(loginAdminDTO.getAdminName())
                        .appName(appConfigQO.getAppName())
                        .packageName(appConfigQO.getPackageName())
                        .appSign(appConfigQO.getAppSign())
                        .build())
                .collect(Collectors.toList());
        this.saveBatch(appConfigDOList);
        String content = "应用配置添加" + StringUtils.join(appNameSet, ",");
        logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), content, MODULE, null);
        return ResponseResult.success();
    }

    private void checkAppConfigQOList(List<AppConfigQO> appConfigQOList) {
        Set<String> packageNameSet = appConfigQOList.stream()
                .map(appConfigQO -> {
                    if (StringUtils.isNotBlank(appConfigQO.getAppSign())) {
                        return appConfigQO.getPackageName() + appConfigQO.getAppSign();
                    }
                    return appConfigQO.getPackageName();
                })
                .collect(Collectors.toSet());
        if (packageNameSet.size() != appConfigQOList.size()) {
            throw new ServiceException("包名和签名存在重复，请检查");
        }
    }

    @Override
    public ResponseResult update(AppConfigQO appConfigQO, LoginAdminDTO loginAdminDTO) {
        // 判重
        checkDuplicationUpdate(appConfigQO, loginAdminDTO);
        AppConfigDO appConfigDO = AppConfigDO.builder()
                .operator(loginAdminDTO.getAdminName())
                .build();
        BeanUtils.copyProperties(appConfigQO, appConfigDO);
        this.updateById(appConfigDO);
        // 下发
        AppConfigSO appConfigSO = new AppConfigSO();
        BeanUtils.copyProperties(appConfigDO, appConfigSO);
        List<Integer> equipmentIdList = equipmentDao.listEquipmentIdByCompanyId(loginAdminDTO.getCompanyId());
        issuedUserHandler.issuedUser(equipmentIdList, loginAdminDTO.getCompanyId(),
                AppConfigCmdEnum.UPDATE_APP_CONFIG.getCmd(), JSONUtil.toJsonStr(Collections.singletonList(appConfigSO)));
        String content = "应用配置编辑 应用名:" + appConfigQO.getAppName() + "包名:" + appConfigQO.getPackageName();
        logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), content, MODULE, null);
        return ResponseResult.success();
    }

    private void checkDuplicationUpdate(AppConfigQO appConfigQO, LoginAdminDTO loginAdminDTO) {
        Long countPackageName = new LambdaQueryChainWrapper<>(baseMapper)
                .eq(AppConfigDO::getCompanyId, loginAdminDTO.getCompanyId())
                .eq(AppConfigDO::getPackageName, appConfigQO.getPackageName())
                .eq(StringUtils.isNotBlank(appConfigQO.getAppSign()), AppConfigDO::getAppSign, appConfigQO.getAppSign())
                .ne(AppConfigDO::getId, appConfigQO.getId())
                .count();
        if (countPackageName > 0) {
            throw new ServiceException("包名已存在");
        }
    }

    @Override
    public ResponseResult delete(List<Integer> idList, LoginAdminDTO loginAdminDTO) {
        for (AppStrategyInfoService appStrategyInfoService : appStrategyInfoServiceList) {
            if (appStrategyInfoService.checkAppExist(idList, false)) {
                return ResponseResult.failure("应用存在引用 无法删除！");
            }
        }
        List<String> appNameList = baseMapper.selectBatchIds(idList).stream().map(AppConfigDO::getAppName).collect(Collectors.toList());
        baseMapper.deleteBatchIds(idList);

        String content = "删除应用配置 应用名:" + StringUtils.join(appNameList, ",");
        logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), content, MODULE, null);
        return ResponseResult.success();
    }

    @Override
    public ResponseResult importFile(MultipartFile file, LoginAdminDTO loginAdminDTO) throws IOException {
        AppConfigImportDataListener appConfigImportDataListener = new AppConfigImportDataListener(loginAdminDTO.getCompanyId(),
                loginAdminDTO.getAdminName(), this);
        EasyExcel.read(file.getInputStream(), AppConfigImportData.class, appConfigImportDataListener).sheet().doRead();
        logAdminHandler.log(loginAdminDTO, LogAdminTypeEnum.APP_TYPE.getLogType(), "应用配置导入", MODULE, null);
        return ResponseResult.success();
    }
}