package digital.laboratory.platform.entrustment.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import digital.laboratory.platform.common.core.constant.CommonConstants;
import digital.laboratory.platform.common.core.constant.OSSDirectoryConstants;
import digital.laboratory.platform.common.core.util.R;
import digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.common.oss.service.OssFile;
import digital.laboratory.platform.entrustment.entity.CaseEvent;
import digital.laboratory.platform.entrustment.entity.CaseEvidence;
import digital.laboratory.platform.entrustment.entity.Entrustment;
import digital.laboratory.platform.entrustment.entity.EntrustmentIdentificationMaterial;
import digital.laboratory.platform.entrustment.mapper.CaseEventMapper;
import digital.laboratory.platform.othersys.vo.EntrustDataVo;
import digital.laboratory.platform.entrustment.service.CaseEventService;
import digital.laboratory.platform.entrustment.service.CaseEvidenceService;
import digital.laboratory.platform.entrustment.service.EntrustmentIdentificationMaterialService;
import digital.laboratory.platform.entrustment.service.EntrustmentService;
import digital.laboratory.platform.entrustment.vo.CaseEventVO;
import digital.laboratory.platform.sys.entity.SysOrg;
import digital.laboratory.platform.sys.feign.RemoteOrgService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;


/**
 * 案件事件服务实现类
 *
 * @author Zhang Xiaolong created at  2022-03-22
 * @describe 案件事件服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CaseEventServiceImpl extends ServiceImpl<CaseEventMapper, CaseEvent> implements CaseEventService {
    private final CaseEventMapper caseEventMapper;
    private final RemoteOrgService remoteOrgService;
    private final CaseEvidenceService caseEvidenceService;
    @Resource
    private EntrustmentService entrustmentService;

    private final OssFile ossFile;
    @Resource

    private EntrustmentIdentificationMaterialService entrustmentIdentificationMaterialService;

    /**
     * 按查询条件查询案件VO
     *
     * @param fromDate
     * @param toDate
     * @param caseName
     * @param caseType
     * @return
     */
    @Override
    public List<CaseEventVO> getCaseVoList(String fromDate, String toDate, String caseName, String caseType) {
        return caseEventMapper.getCaseVoList(fromDate, toDate, caseName, caseType);
    }

    @Override
    public IPage<CaseEventVO> getCaseVoPage(IPage<CaseEvent> page, QueryWrapper<CaseEvent> qw) {
        IPage<CaseEventVO> r = caseEventMapper.getCaseVoPage(page, qw);
        return r;
    }

    /**
     * 根据案件编号查 Id
     *
     * @param caseNo
     * @return
     */
    @Override
    public CaseEvent getByCaseNo(String caseNo) {
        return caseEventMapper.selectOne(Wrappers.<CaseEvent>query().eq("case_no", caseNo));
    }

    /**
     * 根据 Id 查询
     *
     * @param id
     * @return
     */
    @Override
    public CaseEventVO getCaseVOById(String id) {
        return caseEventMapper.getCaseVOById(id);
    }


    /**
     * 生成新的案件编码, 本函数仅用于没有现勘系统、没有案事件系统的情况下
     * 如果有现勘系统, 则使用现勘系统的案件编号。
     * 如果有案事件系统, 则使用案事件系统的案件编号。
     * <p>
     * 格式:
     * A <办案机构 12位> <年月6位> <顺序号4位>
     * 例如:
     * A 520101 040000 202203 0002
     * 合计23位
     * 以为贵州省为例, 组织机构编码为 12 位长度, 除使用数字(0~9)之外, 还使用了英文字母(A~Z)
     * <p>
     * 作为兼容性考虑, 如果机构编码不足 12 位, 以实际位数为准
     *
     * @param caseOwnOrgCode
     * @param date
     * @return
     */
    @Override
    public String getNewCaseCode(String caseOwnOrgCode, LocalDate date) {
        String prefix = CommonConstants.CODE_PREFIX_CASE + caseOwnOrgCode + date.format(DateTimeFormatter.ofPattern("yyyyMM"));

        int newCount = 1;

        // 根据前缀查询最大案件编码
        String maxno = caseEventMapper.getMaxCaseNo(prefix);
        if (maxno != null) {
            String strCount = StrUtil.removePrefix(maxno, prefix);
            try {
                int maxcount = Integer.parseUnsignedInt(strCount);
                newCount = maxcount + 1;
            } catch (NumberFormatException e) {
                // 如果后缀有非数字, 则无视之, 重头编码
                newCount = 1;
            }
        }

        String newCode = prefix + String.format("%04d", newCount);

        return newCode;
    }

    /**
     * 同步禁毒大数据平台上的案件信息
     *
     * @return
     */
    @Override
    public Map<String, List<Map<String, String>>> syncCaseEventInfo(EntrustDataVo entrustDataVo, String caseId, Boolean isUpdate) {

//		List<Map<String, List<Map<String, String>>>> caseEventList = null;
//		List<EntrustDataVo> entrustDataVoList = dataModeChildVo.getList();

//		for (int i = 0; i < entrustDataVoList.size(); i++) {

//			EntrustDataVo entrustDataVo = entrustDataVoList.get(i);
        CaseEvent caseEvent = new CaseEvent();
        if (isUpdate) {
            // 更新数据
            if (StrUtil.isBlank(caseId)) {
                throw new RuntimeException("案件id不能为空");
            }
            CaseEvent event = this.getById(caseId);
            if (event == null) {
                throw new RuntimeException(String.format("id为 %s 的案件找不到", caseId));
            }
            caseEvent = dealDataToCaseEvent(entrustDataVo);
            caseEvent.setId(caseId);
        } else {
            // 新插入数据
            caseEvent = dealDataToCaseEvent(entrustDataVo);
            caseEvent.setId(IdWorker.get32UUID().toUpperCase());
        }

        Map<String, List<Map<String, String>>> entrustDataVoMap = new HashMap<>();
        if (this.saveOrUpdate(caseEvent)) {
            List<Map<String, String>> caseEvidences = caseEvidenceService.syncCaseEvidenceInfo(entrustDataVo, caseEvent, isUpdate);
            entrustDataVoMap.put(caseEvent.getId(), caseEvidences);
        } else {
            throw new RuntimeException("数据异常");
        }

        return entrustDataVoMap;
    }
    //检查案件是否能修改

    @Override
    public Boolean checkCaseIsEnableModify(String caseId) {
        List<Entrustment> entrustmentList = entrustmentService.list(Wrappers.<Entrustment>query()
                .eq("case_id", caseId));
        boolean ret = true;
        for (Entrustment entrustment : entrustmentList) {
            if (entrustment.getStatus() > 1) {
                ret = false;
                break;
            }
        }
        return ret;
    }

    public CaseEvent dealDataToCaseEvent(EntrustDataVo entrustDataVo) {
        CaseEvent caseEvent = new CaseEvent();

        LocalDate happenTime = null;
        if (StrUtil.isNotBlank(entrustDataVo.getSubmitTime())) {
            happenTime = LocalDate.parse(entrustDataVo.getSubmitTime(),
                    DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        } else {
            throw new RuntimeException("案发时间未填");
        }

        caseEvent.setDataSources(1);//设置数据是来自何处
        caseEvent.setCaseName(entrustDataVo.getCaseName()); // 案件名称
//		caseEvent.setId(IdWorker.get32UUID().toUpperCase());
        caseEvent.setCaseOwnOrgId(entrustDataVo.getCreateUserDeptRegionCode()); // 案件所属机构

        caseEvent.setHappenTime(happenTime); // 案件发生时间
        caseEvent.setCaseType("AJLB.100.06070000.06070100.06070102"); // 默认为贩卖毒品案
        caseEvent.setCaseBrief(entrustDataVo.getCaseRemark());
        caseEvent.setThirdPartySysNo(entrustDataVo.getCaseCode());//设置案件编号
        caseEvent.setComments("接口录入");

        if (StrUtil.isBlank(caseEvent.getCaseNo())) {
            // 如果没有提供案件编码, 生成一个
//            Date happenTime1 = Date.from(caseEvent.getHappenTime().atZone(ZoneId.systemDefault()).toInstant());
            if (StrUtil.isNotBlank(caseEvent.getCaseOwnOrgId())) {
                caseEvent.setCaseNo(this.getNewCaseCode(caseEvent.getCaseOwnOrgId(), caseEvent.getHappenTime()));
            } else if (StrUtil.isNotBlank(entrustDataVo.getEntrustOrganization())) {
                SysOrg sysOrg = new SysOrg();
                System.out.println("---------------------------------------" + entrustDataVo.getEntrustOrganization());
                sysOrg.setName(entrustDataVo.getEntrustOrganization());
                R<List<SysOrg>> listR = remoteOrgService.innerGetOrgList(sysOrg);
                if (listR.getCode() == CommonConstants.SUCCESS) {
                    if (listR.getData().size() > 0) {
                        caseEvent.setCaseNo(this.getNewCaseCode(listR.getData().get(0).getOrgCode(), caseEvent.getHappenTime()));
                    } else {
                        caseEvent.setCaseNo(this.getNewCaseCode(entrustDataVo.getCityCode(), caseEvent.getHappenTime()));
                    }

                }
            }

            // 如果还是案件编号还是空，则使用市的编码生成编号
            if (StrUtil.isBlank(caseEvent.getCaseNo())) {
                caseEvent.setCaseNo(this.getNewCaseCode(entrustDataVo.getCityCode(), caseEvent.getHappenTime()));
            }


//			if ( (caseEvent.getHappenTime() != null) && (StrUtil.isNotBlank(caseEvent.getCaseOwnOrgId()))) {
//				SysOrg caseOwnOrg = null;
//				R r = remoteOrgService.getById(caseEvent.getCaseOwnOrgId());
//				if (r.getCode() == CommonConstants.SUCCESS) {
//					caseOwnOrg = (SysOrg) r.getData();
//
//					Date happenTime1 =Date.from(caseEvent.getHappenTime().atZone( ZoneId.systemDefault()).toInstant());;
//					caseEvent.setCaseNo(this.getNewCaseCode(caseOwnOrg.getOrgCode(), happenTime1));
//				}
//				else {
//					throw new RuntimeException(String.format("没有找到 orgId 为 %s 的机构, 请确认案件所属机构(CaseOwnOrg)的正确性!", caseEvent.getCaseOwnOrgId()));
//				}
//			}
        }

        return caseEvent;
    }

    @Override
    public boolean postAddObject(CaseEvent caseEvent) {

        if (StrUtil.isBlank(caseEvent.getCaseNo())) {
            // 如果没有提供案件编码, 生成一个

            if ((caseEvent.getHappenTime() != null) && (StrUtil.isNotBlank(caseEvent.getCaseOwnOrgId()))) {
                SysOrg caseOwnOrg = null;
                R r = remoteOrgService.getById(caseEvent.getCaseOwnOrgId());
                if (r.getCode() == CommonConstants.SUCCESS) {
                    caseOwnOrg = (SysOrg) r.getData();
//                    Date happenTime = Date.from(caseEvent.getHappenTime().atZone(ZoneId.systemDefault()).toInstant());

                    caseEvent.setCaseNo(this.getNewCaseCode(caseOwnOrg.getOrgCode(), caseEvent.getHappenTime()));
                } else {
                    throw new RuntimeException(String.format("没有找到 orgId 为 %s 的机构, 请确认案件所属机构(CaseOwnOrg)的正确性!", caseEvent.getCaseOwnOrgId()));
                }
            }
        }
        caseEvent.setId(IdWorker.get32UUID().toUpperCase());
        return this.save(caseEvent);
    }

    @Override
    public CaseEvent deleteById(String id, DLPUser dlpUser) throws Exception {

        CaseEvent ce = this.getById(id);
        if (ce == null) {
            throw new RuntimeException(String.format("不存在 caseId 为 %s 的案件!", id));
        }
        if (!dlpUser.isStaff()) {
            // 不是鉴定中心员工, 检查一下案件所属机构与用户是不是同一机构
            if (StrUtil.isBlank(ce.getCaseOwnOrgId()) || (!StrUtil.equalsIgnoreCase(ce.getCaseOwnOrgId(), dlpUser.getOrgId()))) {
                throw new RuntimeException(String.format("只能删除自己单位的案件!"));
            }
        }
        List<Entrustment> entrustmentList = entrustmentService.list(Wrappers.<Entrustment>query()
                .eq("case_id", id)
        );
        for (Entrustment e : entrustmentList) {
            //if (StrUtil.isNotBlank(e.getProcessInstanceId())) {
            if (e.getStatus() > 1) {
                throw new RuntimeException(String.format("这个案件的委托 %s 已经提交过, 不能删除!", e.getEntrustmentNo()));
            }
        }
        //--- 到这里, 没有委托或者所有委托都没有提交过, 原则上可删除这个案件 ---
        // 我们要按顺序删除案件相关的东西

        for (Entrustment e : entrustmentList) {
            // 删除全部检材
            List<EntrustmentIdentificationMaterial> eimList = entrustmentIdentificationMaterialService.list(Wrappers.<EntrustmentIdentificationMaterial>query().eq("entrustment_id", e.getId()));
            for (EntrustmentIdentificationMaterial eim : eimList) {
                // 删除检材的全部附件
                List<String> attList = ossFile.fileList(OSSDirectoryConstants.ENTRUSTMENT_DIRECTORY + "/" + eim.getEntrustmentId() + "/" + eim.getId());
                for (String attName : attList) {
                    ossFile.fileDelete(OSSDirectoryConstants.ENTRUSTMENT_DIRECTORY + "/" + eim.getEntrustmentId() + "/" + eim.getId() + "/" + attName);
                }
                // 删除检材本身
                entrustmentIdentificationMaterialService.removeById(eim.getId());
            }

            // 删除委托的全部附件
            List<String> attList = ossFile.fileList(OSSDirectoryConstants.ENTRUSTMENT_DIRECTORY + "/" + e.getId());
            for (String attName : attList) {
                ossFile.fileDelete(OSSDirectoryConstants.ENTRUSTMENT_DIRECTORY + "/" + e.getId() + "/" + attName);
            }

            // 删除委托本身
            entrustmentService.removeById(e.getId());
        }

        // 删除全部物证
        List<CaseEvidence> evidenceList = caseEvidenceService.list(Wrappers.<CaseEvidence>query().eq("case_id", id));
        for (CaseEvidence evidence : evidenceList) {
            // 删除物证的全部附件
            List<String> attList = ossFile.fileList(OSSDirectoryConstants.CASE_DIRECTORY + "/" + evidence.getCaseId() + "/" + evidence.getId());
            for (String attName : attList) {
                ossFile.fileDelete(OSSDirectoryConstants.CASE_DIRECTORY + "/" + evidence.getCaseId() + "/" + evidence.getId() + "/" + attName);
            }
            // 删除物证本身
            caseEvidenceService.removeById(evidence.getId());
        }
        // 删除案件的全部附件
        List<String> attList = ossFile.fileList(OSSDirectoryConstants.CASE_DIRECTORY + "/" + id);
        for (String attName : attList) {
            ossFile.fileDelete(OSSDirectoryConstants.CASE_DIRECTORY + "/" + id + "/" + attName);
        }
        if (this.removeById(id)) {
            return ce;
        } else {
            return null;
        }
    }

}
