package cn.iocoder.yudao.module.bpm.api.task;

import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.business.BpmBusinessFormDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.business.BpmBusinessFormMapper;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.service.business.BpmBusinessFormService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.bpm.BpmCheckInApi;
import cn.iocoder.yudao.module.system.api.bpm.BpmElderlyApi;
import cn.iocoder.yudao.module.system.api.bpm.BpmElderlyChangeApi;
import cn.iocoder.yudao.module.system.api.bpm.BpmElderlyExpenseApi;
import cn.iocoder.yudao.module.system.api.bpm.vo.ElderlyChangeRecordReqVO;
import cn.iocoder.yudao.module.system.api.bpm.vo.ElderlyRetreatRecordRespVO;
import cn.iocoder.yudao.module.system.enums.change.BusinessTypeEnum;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;

import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;

/**
 * Flowable 流程实例 Api 实现类
 *
 * @author 芋道源码
 * @author jason
 */
@Service
@Validated
public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi {

    @Resource
    private BpmProcessInstanceService processInstanceService;

    @Resource
    private HistoryService historyService;

    @Resource
    private BpmBusinessFormService businessFormService;

    @Resource
    private TaskService taskService;

    @Resource
    private BpmBusinessFormMapper businessFormMapper;

    @Resource
    private BpmElderlyChangeApi elderlyChangeApi;

    @Resource
    private BpmElderlyApi bpmElderlyApi;

    @Resource
    private BpmElderlyExpenseApi bpmElderlyExpenseApi;


    @Override
    public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) {
        return processInstanceService.createProcessInstance(userId, reqDTO);
    }

    @Override
    public List<String> getApproverList(String processInstanceId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
        List<HistoricTaskInstance> historicTaskInstances = historicTaskInstanceQuery
                .processInstanceId(processInstanceId)
                .list();
        List<String> approvers = new ArrayList<>();
        for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
            String assignee = historicTaskInstance.getAssignee();
            if (assignee != null) {
                approvers.add(assignee);
            }
        }
        return approvers;
    }

    @Override
    public String getProcessInstanceId(String businessKey) {
        BpmBusinessFormDO businessFormDO = businessFormService.getBusinessFormByBusinessId(businessKey);
        String processInstanceId = "";
        if (null != businessFormDO) {
            processInstanceId = businessFormDO.getProcessInstanceId();
        }
        return processInstanceId;
    }

    @Override
    public Boolean timedClosureProcess() {
//        LocalDate nowLocalDate = LocalDate.now();
        LocalDate nowLocalDate = LocalDate.of(2025, 02, 28);
        LocalDate endDayDate = nowLocalDate.with(TemporalAdjusters.lastDayOfMonth());
        if (!nowLocalDate.isEqual(endDayDate)) {
            return false;
        }

        HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .processInstanceTenantId(FlowableUtils.getTenantId())
                .orderByProcessInstanceStartTime().desc();
        processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, 1);
        List<HistoricProcessInstance> processInstanceList = processInstanceQuery.list();
        processInstanceList.forEach(processInstance -> {

            TaskQuery taskQuery = taskService.createTaskQuery()
                    .active()
                    .processInstanceId(processInstance.getId())
                    .includeProcessVariables()
                    .orderByTaskCreateTime().desc();
            List<Task> list = taskQuery.list();
            list.forEach(task -> {
                BpmProcessInstanceCancelReqVO cancelReqVO = new BpmProcessInstanceCancelReqVO();
                cancelReqVO.setId(processInstance.getId());
                cancelReqVO.setReason("未按时审批，系统自动取消");
                cancelReqVO.setIsForce(Boolean.TRUE);
                processInstanceService.cancelProcessInstanceByStartUser(getLoginUserId(), cancelReqVO);
            });
        });


        return Boolean.TRUE;
    }

    @Override
    public Boolean processInstanceComplete() {

        List<BpmBusinessFormDO> bpmBusinessFormDOS = businessFormMapper.selectList(
                new LambdaQueryWrapperX<BpmBusinessFormDO>()
                        .in(BpmBusinessFormDO::getStatus, 2, 5)
                        .eq(BpmBusinessFormDO::getCompleteStatus, 0));

        if (null == bpmBusinessFormDOS || bpmBusinessFormDOS.size() == 0) {
            return Boolean.TRUE;
        }
        bpmBusinessFormDOS.forEach(bpmBusinessFormDO -> {
            Integer type = bpmBusinessFormDO.getType();
            if (BusinessTypeEnum.APPLY_RETREAT.getValue().equals(type)) {
                bpmElderlyApi.releaseBed(bpmBusinessFormDO.getBusinessId());
                bpmElderlyExpenseApi.generateRefundSettlementOrder(bpmBusinessFormDO.getBusinessId(), bpmBusinessFormDO.getStartTenantId());
                BpmBusinessFormDO updateDO = new BpmBusinessFormDO();
                updateDO.setId(bpmBusinessFormDO.getId());
                updateDO.setCompleteStatus(1);
                businessFormMapper.updateById(updateDO);
            }

            if (BusinessTypeEnum.BED_CHANGE.getValue().equals(type)) {
                elderlyChangeApi.generateBill(bpmBusinessFormDO.getBusinessId(), 1, bpmBusinessFormDO.getStartTenantId());
                elderlyChangeApi.convertBed(bpmBusinessFormDO.getBusinessId());
                BpmBusinessFormDO updateDO = new BpmBusinessFormDO();
                updateDO.setId(bpmBusinessFormDO.getId());
                updateDO.setCompleteStatus(1);
                businessFormMapper.updateById(updateDO);
            }

            if (BusinessTypeEnum.NURSE_CHANGE.getValue().equals(type)) {
                elderlyChangeApi.generateBill(bpmBusinessFormDO.getBusinessId(), 2, bpmBusinessFormDO.getStartTenantId());
                BpmBusinessFormDO updateDO = new BpmBusinessFormDO();
                updateDO.setId(bpmBusinessFormDO.getId());
                updateDO.setCompleteStatus(1);
                businessFormMapper.updateById(updateDO);
            }

            if (BusinessTypeEnum.CATERING_CHANGE.getValue().equals(type)) {
                elderlyChangeApi.generateBill(bpmBusinessFormDO.getBusinessId(), 3, bpmBusinessFormDO.getStartTenantId());
                BpmBusinessFormDO updateDO = new BpmBusinessFormDO();
                updateDO.setId(bpmBusinessFormDO.getId());
                updateDO.setCompleteStatus(1);
                businessFormMapper.updateById(updateDO);
            }

            if (BusinessTypeEnum.PRICE_CHANGE.getValue().equals(type)) {
                elderlyChangeApi.generatePriceChangeBill(bpmBusinessFormDO.getBusinessId());
                BpmBusinessFormDO updateDO = new BpmBusinessFormDO();
                updateDO.setId(bpmBusinessFormDO.getId());
                updateDO.setCompleteStatus(1);
                businessFormMapper.updateById(updateDO);
            }


        });

        return Boolean.TRUE;
    }

    @Override
    public Integer insertBpmBusinessFormDO(Long businessId, Long businessId2, Long tenantId) {
        BpmBusinessFormDO businessFormDO = new BpmBusinessFormDO();
        businessFormDO.setBusinessId(businessId);
        businessFormDO.setBusinessId2(businessId2);
        businessFormDO.setUserId(getLoginUserId());
        businessFormDO.setStatus(5);
        businessFormDO.setReadStatus(1);
        businessFormDO.setCompleteStatus(1);
        businessFormDO.setStartTenantId(tenantId);
        businessFormDO.setType(1);
        return businessFormMapper.insert(businessFormDO);
    }
}
