package com.orion.visor.module.asset.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.lang.utils.collect.Lists;
import com.orion.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.framework.security.core.utils.SecurityUtils;
import com.orion.visor.module.asset.convert.ExecTemplateConvert;
import com.orion.visor.module.asset.dao.ExecTemplateDAO;
import com.orion.visor.module.asset.entity.domain.ExecTemplateDO;
import com.orion.visor.module.asset.entity.request.exec.ExecTemplateCreateRequest;
import com.orion.visor.module.asset.entity.request.exec.ExecTemplateQueryRequest;
import com.orion.visor.module.asset.entity.request.exec.ExecTemplateUpdateRequest;
import com.orion.visor.module.asset.entity.vo.ExecTemplateVO;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.enums.ScriptExecEnum;
import com.orion.visor.module.asset.service.AssetAuthorizedDataService;
import com.orion.visor.module.asset.service.ExecTemplateHostService;
import com.orion.visor.module.asset.service.ExecTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 执行模板 服务实现类
 *
 * @author Jiahang Li
 * @version 1.0.1
 * @since 2024-3-7 18:08
 */
@Slf4j
@Service
public class ExecTemplateServiceImpl implements ExecTemplateService {

    @Resource
    private ExecTemplateDAO execTemplateDAO;

    @Resource
    private ExecTemplateHostService execTemplateHostService;

    @Resource
    private AssetAuthorizedDataService assetAuthorizedDataService;

    @Override
    public Long createExecTemplate(ExecTemplateCreateRequest request) {
        log.info("ExecTemplateService-createExecTemplate request: {}", JSON.toJSONString(request));
        Valid.valid(ScriptExecEnum::of, request.getScriptExec());
        // 转换
        ExecTemplateDO record = ExecTemplateConvert.MAPPER.to(request);
        // 查询数据是否冲突
        this.checkExecTemplatePresent(record);
        // 插入模板
        int effect = execTemplateDAO.insert(record);
        Long id = record.getId();
        // 修改模板主机
        execTemplateHostService.setTemplateHost(id, request.getHostIdList());
        log.info("ExecTemplateService-createExecTemplate id: {}, effect: {}", id, effect);
        return id;
    }

    @Override
    public Integer updateExecTemplateById(ExecTemplateUpdateRequest request) {
        Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING);
        Valid.valid(ScriptExecEnum::of, request.getScriptExec());
        log.info("ExecTemplateService-updateExecTemplateById id: {}, request: {}", id, JSON.toJSONString(request));
        // 查询
        ExecTemplateDO record = execTemplateDAO.selectById(id);
        Valid.notNull(record, ErrorMessage.DATA_ABSENT);
        // 转换
        ExecTemplateDO updateRecord = ExecTemplateConvert.MAPPER.to(request);
        // 查询数据是否冲突
        this.checkExecTemplatePresent(updateRecord);
        // 更新模板
        int effect = execTemplateDAO.updateById(updateRecord);
        // 修改模板主机
        execTemplateHostService.setTemplateHost(id, request.getHostIdList());
        log.info("ExecTemplateService-updateExecTemplateById effect: {}", effect);
        return effect;
    }

    @Override
    public ExecTemplateVO getExecTemplateById(Long id) {
        // 查询模板
        ExecTemplateDO record = execTemplateDAO.selectById(id);
        Valid.notNull(record, ErrorMessage.DATA_ABSENT);
        // 转换
        ExecTemplateVO template = ExecTemplateConvert.MAPPER.to(record);
        // 查询模板主机
        Set<Long> hosts = execTemplateHostService.getHostByTemplateId(id);
        template.setHostIdList(hosts);
        return template;
    }

    @Override
    public ExecTemplateVO getExecTemplateWithAuthorized(Long id) {
        // 查询模板
        ExecTemplateDO record = execTemplateDAO.selectById(id);
        Valid.notNull(record, ErrorMessage.DATA_ABSENT);
        // 转换
        ExecTemplateVO template = ExecTemplateConvert.MAPPER.to(record);
        // 查询模板主机
        Set<Long> hostIdList = execTemplateHostService.getHostByTemplateId(id);
        if (Lists.isEmpty(hostIdList)) {
            return template;
        }
        // 过滤认证的主机
        List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH);
        hostIdList.removeIf(s -> !authorizedHostIdList.contains(s));
        template.setHostIdList(hostIdList);
        return template;
    }

    @Override
    public DataGrid<ExecTemplateVO> getExecTemplatePage(ExecTemplateQueryRequest request) {
        // 条件
        LambdaQueryWrapper<ExecTemplateDO> wrapper = this.buildQueryWrapper(request);
        // 查询模板
        return execTemplateDAO.of(wrapper)
                .page(request)
                .dataGrid(ExecTemplateConvert.MAPPER::to);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteExecTemplateById(Long id) {
        return this.deleteExecTemplateByIdList(Lists.singleton(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteExecTemplateByIdList(List<Long> idList) {
        log.info("ExecTemplateService-deleteExecTemplateByIdList idList: {}", idList);
        // 检查数据是否存在
        List<ExecTemplateDO> recordList = execTemplateDAO.selectBatchIds(idList);
        Valid.notEmpty(recordList, ErrorMessage.DATA_ABSENT);
        // 设置日志参数
        String name = recordList.stream()
                .map(ExecTemplateDO::getName)
                .collect(Collectors.joining(Const.COMMA));
        OperatorLogs.add(OperatorLogs.NAME, name);
        // 删除模板
        int effect = execTemplateDAO.deleteBatchIds(idList);
        log.info("ExecTemplateService-deleteExecTemplateByIdList idList: {}, effect: {}", idList, effect);
        // 删除模板主机
        effect += execTemplateHostService.deleteByTemplateIdList(idList);
        return effect;
    }

    /**
     * 检查对象是否存在
     *
     * @param domain domain
     */
    private void checkExecTemplatePresent(ExecTemplateDO domain) {
        // 构造条件
        LambdaQueryWrapper<ExecTemplateDO> wrapper = execTemplateDAO.wrapper()
                // 更新时忽略当前记录
                .ne(ExecTemplateDO::getId, domain.getId())
                // 用其他字段做重复校验
                .eq(ExecTemplateDO::getName, domain.getName());
        // 检查是否存在
        boolean present = execTemplateDAO.of(wrapper).present();
        Valid.isFalse(present, ErrorMessage.DATA_PRESENT);
    }

    /**
     * 构建查询 wrapper
     *
     * @param request request
     * @return wrapper
     */
    private LambdaQueryWrapper<ExecTemplateDO> buildQueryWrapper(ExecTemplateQueryRequest request) {
        return execTemplateDAO.wrapper()
                .eq(ExecTemplateDO::getId, request.getId())
                .like(ExecTemplateDO::getName, request.getName())
                .like(ExecTemplateDO::getCommand, request.getCommand())
                .orderByDesc(ExecTemplateDO::getId);
    }

}
