package cn.stylefeng.workflow.instance.modular.draft.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.entity.BaseEntity;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.workflow.api.DefinitionApi;
import cn.stylefeng.workflow.api.entity.design.Definition;
import cn.stylefeng.workflow.instance.api.factory.RuntimeInstanceFactory;
import cn.stylefeng.workflow.instance.api.pojo.request.WorkflowSaveDraftRequest;
import cn.stylefeng.workflow.instance.api.pojo.task.CommonTaskItem;
import cn.stylefeng.workflow.instance.modular.draft.entity.FlowEngineDraft;
import cn.stylefeng.workflow.instance.modular.draft.enums.FlowEngineDraftExceptionEnum;
import cn.stylefeng.workflow.instance.modular.draft.factory.DraftFactory;
import cn.stylefeng.workflow.instance.modular.draft.mapper.FlowEngineDraftMapper;
import cn.stylefeng.workflow.instance.modular.draft.pojo.request.FlowEngineDraftRequest;
import cn.stylefeng.workflow.instance.modular.draft.service.FlowEngineDraftService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class FlowEngineDraftServiceImpl extends ServiceImpl<FlowEngineDraftMapper, FlowEngineDraft> implements FlowEngineDraftService {

    @Resource
    private DefinitionApi definitionApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(WorkflowSaveDraftRequest workflowSaveDraftRequest) {

        Long draftId = workflowSaveDraftRequest.getDraftId();
        FlowEngineDraft flowEngineDraft = null;
        if (ObjectUtil.isEmpty(draftId)) {
            flowEngineDraft = new FlowEngineDraft();
        } else {
            flowEngineDraft = this.getById(draftId);
            if (ObjectUtil.isEmpty(flowEngineDraft)) {
                flowEngineDraft = new FlowEngineDraft();
            }
        }

        flowEngineDraft.setDefinitionId(workflowSaveDraftRequest.getDefinitionId());

        flowEngineDraft.setInstanceVariable(workflowSaveDraftRequest.getInstanceVariable());

        Definition definitionInfo = definitionApi.getDefinitionInfo(flowEngineDraft.getDefinitionId());
        flowEngineDraft.setModelId(definitionInfo.getModelId());

        String instanceTitle = RuntimeInstanceFactory.createInstanceTitle(definitionInfo, workflowSaveDraftRequest.getInstanceVariable());
        flowEngineDraft.setDraftTitle(instanceTitle);

        flowEngineDraft.setApplicant(LoginContext.me().getLoginUser().getUserId());

        flowEngineDraft.setApplicantOrgId(LoginContext.me().getCurrentUserCompanyId());

        this.saveOrUpdate(flowEngineDraft);
    }

    @Override
    public PageResult<CommonTaskItem> findPage(FlowEngineDraftRequest flowEngineDraftRequest) {
        LambdaQueryWrapper<FlowEngineDraft> wrapper = createWrapper(flowEngineDraftRequest);

        wrapper.select(FlowEngineDraft::getDraftId, FlowEngineDraft::getDefinitionId, FlowEngineDraft::getApplicant,
                FlowEngineDraft::getDraftTitle, FlowEngineDraft::getApplicantOrgId, BaseEntity::getCreateTime);

        Page<FlowEngineDraft> pageList = this.page(PageFactory.defaultPage(), wrapper);

        List<FlowEngineDraft> records = pageList.getRecords();

        List<CommonTaskItem> draftResult = DraftFactory.createDraftResult(records);

        return PageResultFactory.createPageResult(draftResult, pageList.getTotal(), Convert.toInt(pageList.getSize()),
                Convert.toInt(pageList.getCurrent()));
    }

    @Override
    public FlowEngineDraft getDetail(FlowEngineDraftRequest flowEngineDraftRequest) {

        Long draftId = flowEngineDraftRequest.getDraftId();

        LambdaQueryWrapper<FlowEngineDraft> flowEngineDraftLambdaQueryWrapper = new LambdaQueryWrapper<>();
        flowEngineDraftLambdaQueryWrapper.eq(FlowEngineDraft::getDraftId, draftId);
        flowEngineDraftLambdaQueryWrapper.select(FlowEngineDraft::getDraftId, FlowEngineDraft::getDraftTitle,
                FlowEngineDraft::getInstanceVariable);
        FlowEngineDraft flowEngineDraft = this.getOne(flowEngineDraftLambdaQueryWrapper, false);

        if (ObjectUtil.isEmpty(flowEngineDraft)) {
            throw new ServiceException(FlowEngineDraftExceptionEnum.FLOW_ENGINE_DRAFT_NOT_EXISTED);
        }

        return flowEngineDraft;
    }

    private FlowEngineDraft queryFlowEngineDraft(FlowEngineDraftRequest flowEngineDraftRequest) {
        FlowEngineDraft flowEngineDraft = this.getById(flowEngineDraftRequest.getDraftId());
        if (ObjectUtil.isEmpty(flowEngineDraft)) {
            throw new ServiceException(FlowEngineDraftExceptionEnum.FLOW_ENGINE_DRAFT_NOT_EXISTED);
        }
        return flowEngineDraft;
    }

    private LambdaQueryWrapper<FlowEngineDraft> createWrapper(FlowEngineDraftRequest flowEngineDraftRequest) {
        LambdaQueryWrapper<FlowEngineDraft> queryWrapper = new LambdaQueryWrapper<>();

        if (ObjectUtil.isNotEmpty(flowEngineDraftRequest.getSearchText())) {
            queryWrapper.like(FlowEngineDraft::getDraftTitle, flowEngineDraftRequest.getSearchText());
        }

        return queryWrapper;
    }

}
