package com.testor.module.contractor.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.biz.file.model.dto.FileAjaxDTO;
import com.testor.biz.file.model.dto.FileDTO;
import com.testor.biz.sys.dict.data.model.domain.SysDictData;
import com.testor.common.api.FileController;
import com.testor.common.constant.StatusEnum;
import com.testor.common.model.UpdateProcessStatusReq;
import com.testor.common.util.DateUtil;
import com.testor.module.contractor.common.model.constant.ContractorProcessStatus;
import com.testor.module.contractor.enums.ContractorFlowTypeEnum;
import com.testor.module.contractor.enums.GeneralStatusEnum;
import com.testor.module.contractor.enums.SafetyBriefContentEnum;
import com.testor.module.contractor.ledger.model.domain.TContractorPerson;
import com.testor.module.contractor.ledger.model.domain.TContractorProtectiveEquipment;
import com.testor.module.contractor.ledger.model.dto.TContractorPersonParam;
import com.testor.module.contractor.ledger.model.dto.TContractorProtectiveEquipmentParam;
import com.testor.module.contractor.ledger.service.TContractorPersonService;
import com.testor.module.contractor.ledger.service.TContractorProtectiveEquipmentService;
import com.testor.module.contractor.manage.dao.TContractorSafetyBriefDao;
import com.testor.module.contractor.manage.model.domain.*;
import com.testor.module.contractor.manage.model.dto.*;
import com.testor.module.contractor.manage.service.*;
import com.testor.module.sys.service.NewSysDictDataService;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.biz.models.BaseResponse;
import com.tongtech.tfw.backend.common.context.ContextUtils;
import com.tongtech.tfw.backend.common.exception.BusinessException;
import com.tongtech.tfw.backend.common.models.supers.SuperServiceImpl;
import com.tongtech.tfw.backend.common.models.sys.UserInfo;
import com.tongtech.tfw.backend.core.helper.IdHelper;
import com.tongtech.tfw.backend.core.helper.StringHelper;
import com.tongtech.tfw.backend.core.helper.bean.BeanHelper;
import com.tongtech.tfw.workflow.apis.definition.controller.ProcessDefinitionController;
import com.tongtech.tfw.workflow.apis.definition.model.dto.ProcessDefStartParam;
import com.tongtech.tfw.workflow.apis.task.controller.WfTaskController;
import com.tongtech.tfw.workflow.apis.task.model.dto.CompleteTask;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 承包商管理-安全交底Service业务层处理
 *
 * @author testor-framework
 * @date 2024-11-28 11:51:46
 */
@Service
public class TContractorSafetyBriefServiceImpl extends SuperServiceImpl<TContractorSafetyBriefDao,
        TContractorSafetyBrief> implements TContractorSafetyBriefService {
    Logger logger =  org.slf4j.LoggerFactory.getLogger(TContractorSafetyBriefServiceImpl.class);
    @Autowired(required = false)
    private TContractorSafetyBriefDao tContractorSafetyBriefDao;

    @Autowired
    private NewSysDictDataService newSysDictDataService;

    @Autowired
    private TContractorSafetyBriefDetailService tContractorSafetyBriefDetailService;

    @Autowired
    private TContractorPreparationService tContractorPreparationService;

    @Autowired
    private ProcessDefinitionController processDefinitionController;

    @Autowired
    private WfTaskController wfTaskController;

    @Autowired
    private TContractorAllowService tContractorAllowService;
    @Autowired
    private TContractorAllowPersonService tContractorAllowPersonService;
    @Autowired
    private TContractorPersonService tContractorPersonService;

    @Autowired
    private TContractorAllowProtectiveService tContractorAllowProtectiveService;
    @Autowired
    private TContractorProtectiveEquipmentService tContractorProtectiveEquipmentService;
    @Autowired
    private TContractorPreparationAnalysisService tContractorPreparationAnalysisService;

    @Autowired
    private FileController fileController;

    @Override
    public Page<ContractorSafetyBriefDto> pageList(TContractorSafetyBriefParam param) {
        Long page =
                StringHelper.isEmpty(param.getPage()) ? BizConstants.PAGE : Long.valueOf(param.getPage());
        Long limit =
                StringHelper.isEmpty(param.getLimit()) ? BizConstants.LIMIT : Long.valueOf(param.getLimit());
        Page<TContractorSafetyBrief> resultPage = new Page<>(page, limit);
        UserInfo loginUser = ContextUtils.getLoginUser();
        param.setOrgId(loginUser.getOrgId());
        return tContractorSafetyBriefDao.pageList(resultPage, param);
    }

    @Override
    public ContractorSafetyBriefDto getEntityById(String id) {
        TContractorSafetyBrief data = this.getById(id);
        ContractorSafetyBriefDto dto = BeanHelper.beanToBean(data, ContractorSafetyBriefDto.class);
        List<TContractorSafetyBriefDetail> detailList =
                tContractorSafetyBriefDetailService.list(new QueryWrapper<TContractorSafetyBriefDetail>().eq(TContractorSafetyBriefDetail.BRIEF_ID, id).orderByAsc(TContractorSafetyBriefDetail.TREE_SORT));
        dto.setBriefDetailList(detailList);
        return dto;
    }

    @Override
    public ContractorSafetyBriefContentDto getSafetyBriefContent(TContractorSafetyBriefDetailParam param) {
        ContractorSafetyBriefContentDto dto = new ContractorSafetyBriefContentDto();
        if (SafetyBriefContentEnum.C04.getCode().equals(param.getCode())) {
            // 1. 根据承包商id和项目id查询准入管理数据
            TContractorAllow tContractorAllow = getTContractorAllow(param);
            if (tContractorAllow != null) {
                // 2.查询准入管理对应的人员数据
                List<String> personIdsByAllowId =
                        tContractorAllowPersonService.getIdsByAllowId(tContractorAllow.getId());
                TContractorPersonParam tContractorPersonParam = new TContractorPersonParam();
                tContractorPersonParam.setIds(personIdsByAllowId);
                tContractorPersonParam.setTypeQuery("1");
                tContractorPersonParam.setPage(param.getPage());
                tContractorPersonParam.setLimit(param.getLimit());
                Page<TContractorPerson> tContractorPeople = tContractorPersonService.listEntity(tContractorPersonParam);
                dto.setPersonPage(tContractorPeople);
            }

        } else if (SafetyBriefContentEnum.C05.getCode().equals(param.getCode())) {
            // 1.根据承包商id和项目id查询开工准备数据
            TContractorPreparation preparation =
                    tContractorPreparationService.getByCtractorIdAndProjIdAndBizId(param.getContractorId(),
                            param.getProjId()
                            , param.getBizId());
            if (preparation != null) {
                // 2.查询开工准备中的作业风险数据
                TContractorPreparationAnalysisParam analysisParam = new TContractorPreparationAnalysisParam();
                analysisParam.setPreparationId(preparation.getId());
                analysisParam.setPage(param.getPage());
                analysisParam.setLimit(param.getLimit());
                Page<TContractorPreparationAnalysis> analysisPage =
                        tContractorPreparationAnalysisService.listEntity(analysisParam);
                dto.setPreparationAnalysisPage(analysisPage);
            }

        } else if (SafetyBriefContentEnum.C06.getCode().equals(param.getCode())) {
            // 1. 根据承包商id和项目id查询准入管理数据
            TContractorAllow tContractorAllow = getTContractorAllow(param);
            if (tContractorAllow != null) {
                // 2.查询准入管理对应的防护用具数据
                List<String> protectiveIdsByAllowId =
                        tContractorAllowProtectiveService.getIdsByAllowId(tContractorAllow.getId());
                TContractorProtectiveEquipmentParam tContractorProtectiveEquipmentParam =
                        new TContractorProtectiveEquipmentParam();
                tContractorProtectiveEquipmentParam.setIds(protectiveIdsByAllowId);
                tContractorProtectiveEquipmentParam.setTypeQuery("1");
                tContractorProtectiveEquipmentParam.setPage(param.getPage());
                tContractorProtectiveEquipmentParam.setLimit(param.getLimit());
                Page<TContractorProtectiveEquipment> protectiveEquipmentPage =
                        tContractorProtectiveEquipmentService.listEntity(tContractorProtectiveEquipmentParam);
                dto.setProtectiveEquipmentPage(protectiveEquipmentPage);
            }
        } else if (SafetyBriefContentEnum.C07.getCode().equals(param.getCode())) {
            // 1.根据承包商id和项目id查询开工准备数据
            TContractorPreparation preparation =
                    tContractorPreparationService.getByCtractorIdAndProjIdAndBizId(param.getContractorId(),
                            param.getProjId()
                            , param.getBizId());
            dto.setPreparation(preparation);
        }
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TContractorSafetyBrief addEntity(TContractorSafetyBriefParam addRequest) {
        String id = IdHelper.getId32bit();
        TContractorSafetyBrief data = BeanHelper.beanToBean(addRequest, TContractorSafetyBrief.class);
        data.setId(id);
        // 初始化流程状态为0-待推送
        data.setProcessStatus(ContractorProcessStatus.PENDING_PUSH.getValue());
        boolean result = save(data);

        if (result) {
            // 根据承包商id和项目id查询开工准备数据
            TContractorPreparation preparation =
                    tContractorPreparationService.getByCtractorIdAndProjIdAndBizId(addRequest.getContractorId(),
                            addRequest.getProjId(), addRequest.getBizId());
            // 从开工准备数据初始化安全交底内容明细前3条数据，分别是“C01-作业时间”、“C02-作业地点”、“C03-作业过程描述”
            Map<String, String> contentMap = new HashMap<>();
            String planStartTime =  preparation.getPlanStartTime() != null ?
                    DateUtil.convertDateToStr(preparation.getPlanStartTime(),"yyyy-MM-dd") : "";

            String planEndTime =
                    preparation.getPlanEndTime() != null ? DateUtil.convertDateToStr(preparation.getPlanEndTime(),"yyyy-MM-dd") : "";
            contentMap.put(SafetyBriefContentEnum.C01.getCode(), StringHelper.format("{} ~ {}", planStartTime,
                    planEndTime));
            contentMap.put(SafetyBriefContentEnum.C02.getCode(), preparation.getConstructionLocation());
            contentMap.put(SafetyBriefContentEnum.C03.getCode(), preparation.getConstructionProjectDesc());

            // 初始化条件审查内容明细表数据
            List<SysDictData> dictDataList = newSysDictDataService.getDictByType("contractor_safety_brief_content");
            List<TContractorSafetyBriefDetail> detailList = dictDataList.stream().map(dict -> {
                TContractorSafetyBriefDetail detail = new TContractorSafetyBriefDetail();
                detail.setBriefId(data.getId());
                detail.setCode(dict.getDictKey());
                detail.setContent(dict.getDictValue());
                detail.setTreeSort(dict.getTreeSort());
                String reviewStatus = GeneralStatusEnum.UNPASSED.getCode();
                // 如果审查内容是“C01-作业时间”或者“C02-作业地点”或者“C03-作业过程描述”，则审查状态默认为通过
                if (SafetyBriefContentEnum.C01.getCode().equals(dict.getDictKey()) || SafetyBriefContentEnum.C02.getCode().equals(dict.getDictKey()) || SafetyBriefContentEnum.C03.getCode().equals(dict.getDictKey())) {
                    reviewStatus = GeneralStatusEnum.PASSED.getCode();
                    detail.setContent(StringHelper.format("{}: {}", dict.getDictValue(),
                            contentMap.get(dict.getDictKey())));
                }
                detail.setBriefStatus(reviewStatus);
                detail.setContractorId(data.getContractorId());
                detail.setProjId(data.getProjId());
                detail.setBizId(data.getBizId());
                return detail;
            }).collect(Collectors.toList());
            tContractorSafetyBriefDetailService.saveBatch(detailList);
            return data;
        }
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateEntity(TContractorSafetyBriefParam updateRequest) {
        TContractorSafetyBrief data = BeanHelper.beanToBean(updateRequest, TContractorSafetyBrief.class);
        // 处理接受交底人签字签名图片
        String sign = getSignUrl(updateRequest.getSignature());
        if (StringUtils.isNotEmpty(sign)) {
            data.setSignature(sign);
        }
        boolean result = updateById(data);
        if (result) {
            List<TContractorSafetyBriefDetail> detailList = updateRequest.getBriefDetailList();
            if (StringHelper.isNotEmpty(detailList)) {
                tContractorSafetyBriefDetailService.updateBatchById(detailList);
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProcessStatus(UpdateProcessStatusReq updateProcessStatusReq) throws Exception {
        if (StringHelper.isEmpty(updateProcessStatusReq.getId()) || StringHelper.isEmpty(updateProcessStatusReq.getProcessStatus())) {
            throw new BusinessException("请求参数有误，请联系管理员！");
        }
        this.lambdaUpdate().set(TContractorSafetyBrief::getProcessStatus, updateProcessStatusReq.getProcessStatus())
                .set(StringUtils.isNotEmpty(updateProcessStatusReq.getProcessId()),
                        TContractorSafetyBrief::getProcessId, updateProcessStatusReq.getProcessId())
                .set(StringUtils.isNotEmpty(updateProcessStatusReq.getRejectOpinion()),
                        TContractorSafetyBrief::getRejectOpinion, updateProcessStatusReq.getRejectOpinion())
                .eq(TContractorSafetyBrief::getId, updateProcessStatusReq.getId()).update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startProcess(TContractorSafetyBriefParam updateRequest) {
        // 创建一个ProcessDefStartParam对象，并设置流程定义的key为"contractor"
        ProcessDefStartParam processDefStartParam = new ProcessDefStartParam("contractor");
        // 设置业务主键为updateRequest的id
        processDefStartParam.setBizKey(updateRequest.getId());
        // 创建一个Map对象，并设置type为"brief"
        Map<String, Object> map = new HashMap<>();
        map.put("type", ContractorFlowTypeEnum.BRIEF.getCode());
        // 将Map对象设置到processDefStartParam的variables属性中
        processDefStartParam.setVariables(map);
        // 调用processDefinitionController的startProcessIns方法，并获取返回结果
        String result = processDefinitionController.startProcessIns(processDefStartParam).getData().getResult();
        // 设置processId为result
        updateRequest.setProcessId(result);
        // 设置processStatus为待审核
        updateRequest.setProcessStatus(ContractorProcessStatus.UNDER_REVIEW.getValue());
        // 调用tContractorSafetyBriefService的updateById方法，更新tContractorSafetyBrief对象
        this.updateEntity(updateRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeProcess(TContractorSafetyBriefParam updateRequest) {
        String processStatus = updateRequest.getProcessStatus();
        CompleteTask completeTask = new CompleteTask();
        completeTask.setBizId(updateRequest.getId());
        completeTask.setTaskId(updateRequest.getTaskId());
        // 创建一个vars参数
        Map<String, Object> vars = StringHelper.isEmpty(updateRequest.getVars()) ? new HashMap<>() :
                updateRequest.getVars();
        if (!vars.containsKey("processStatus")) {
            vars.put("processStatus", processStatus);
        }
        completeTask.setVars(vars);
        wfTaskController.completeTask(completeTask).getData().getResult();
        // 创建一个tContractorSafetyBrief对象
        TContractorSafetyBrief tContractorSafetyBrief = new TContractorSafetyBrief();
        // 设置id为updateRequest的id
        tContractorSafetyBrief.setId(updateRequest.getId());
        // 设置processStatus
        tContractorSafetyBrief.setProcessStatus(processStatus);
        if (ContractorProcessStatus.REJECTED.getValue().equals(processStatus)) {
            String rejectOpinion = vars.get("rejectOpinion") == null ? "" : vars.get("rejectOpinion").toString();
            tContractorSafetyBrief.setRejectOpinion(rejectOpinion);
        }
        // 调用tContractorSafetyBriefService的updateById方法，更新tContractorSafetyBrief对象
        boolean result = this.updateById(tContractorSafetyBrief);
    }

    // Private Method
    private TContractorAllow getTContractorAllow(TContractorSafetyBriefDetailParam param) {
        return tContractorAllowService.getOne(new QueryWrapper<TContractorAllow>().eq(TContractorAllow.CONTRACTOR_ID
                        , param.getContractorId()).eq(TContractorAllow.PROJ_ID,
                        param.getProjId()).eq(TContractorAllow.BIZ_ID, param.getBizId()).ne(TContractorAllow.STATUS,
                        StatusEnum.DELETE.getCode()),
                false);
    }

    /**
     * 处理接受交底人签字签名图片
     *
     * @param signBase64 签名图片 base64 编码
     * @return
     */
    private String getSignUrl(String signBase64) {
        String fileUrl = null;
        try {
            if (StringHelper.isNotEmpty(signBase64)
                    && (signBase64.contains("data:image/png;base64,") || signBase64.contains("data:image/svg+xml;base64,"))) {
                String fileName = "";
                FileAjaxDTO fileAjaxDTO = new FileAjaxDTO();
                fileAjaxDTO.setFile(signBase64);
                String str = "";
                if (signBase64.contains("data:image/png;base64,")) {
                    fileName = "接受交底人签字_" + System.currentTimeMillis() + ".png";
                    str = signBase64.replace("data:image/png;base64,", "");
                } else if (signBase64.contains("data:image/svg+xml;base64,")) {
                    fileName = "接受交底人签字_" + System.currentTimeMillis() + ".svg";
                    str = signBase64.replace("data:image/svg+xml;base64,", "");
                }
                fileAjaxDTO.setFileName(fileName);
                int i = str.indexOf("=");
                if (str.indexOf("=") > 0) {
                    str = str.substring(0, i);
                }
                int length = str.length();
                int i1 = length - (length / 8) * 2;
                String s = String.valueOf(i1);
                fileAjaxDTO.setFileSize(s);
                BaseResponse<FileDTO> fileDTOBaseResponse = fileController.uploadBase64(fileAjaxDTO);
                fileUrl = fileDTOBaseResponse.getData().getFilePath();
            }
        }catch(Exception ex){
            logger.error("处理接受交底人签字签名图片异常：" + ex.getMessage(), ex);
        }

        return fileUrl;
    }
}
