package com.njcn.gather.icd.mapping.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njcn.gather.icd.mapping.mapper.CsIcdPathMapper;
import com.njcn.gather.icd.mapping.pojo.param.CsIcdPathParam;
import com.njcn.gather.icd.mapping.pojo.param.IcdCheckResultSaveParam;
import com.njcn.gather.icd.mapping.pojo.po.CsIcdPathPO;
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO;
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO;
import com.njcn.gather.icd.mapping.service.CsIcdPathService;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * ICD 存储记录服务实现。
 */
@Service
@RequiredArgsConstructor
public class CsIcdPathServiceImpl implements CsIcdPathService {

    private static final int STATE_NORMAL = 1;

    private static final int STATE_DELETED = 0;

    private static final int ICD_TYPE_MANUAL_STANDARD = 1;

    private static final int ICD_TYPE_MANUAL_NON_STANDARD = 2;

    private static final int ICD_TYPE_UPSTREAM_STANDARD = 3;

    private static final int ICD_TYPE_UPSTREAM_NON_STANDARD = 4;

    private final CsIcdPathMapper csIcdPathMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public List<CsIcdPathVO> listIcdPaths(CsIcdPathParam.ListParam param) {
        CsIcdPathParam.ListParam checkedParam = param == null ? new CsIcdPathParam.ListParam() : param;
        return csIcdPathMapper.selectIcdPathList(
                trimToNull(checkedParam.getKeyword()),
                checkedParam.getType(),
                checkedParam.getResult());
    }

    @Override
    public List<CsIcdPathVO> listReferenceIcdPaths() {
        return csIcdPathMapper.selectReferenceIcdPathList();
    }

    @Override
    public JsonNode getIcdCheckMsg(String icdId) {
        String id = requireText(icdId, "ICD璁板綍ID涓嶈兘涓虹┖");
        CsIcdPathVO icdPath = csIcdPathMapper.selectIcdCheckMsgById(id);
        return icdPath == null ? null : icdPath.getMsg();
    }

    @Override
    public CsIcdPathDetailVO getMappingDetail(String icdId) {
        String id = requireText(icdId, "ICD记录ID不能为空");
        CsIcdPathDetailVO detail = csIcdPathMapper.selectIcdPathDetailById(id);
        if (detail == null) {
            return null;
        }
        byte[] icdContent = detail.getIcdContent();
        if (icdContent != null && icdContent.length > 0) {
            detail.setIcdText(new String(icdContent, StandardCharsets.UTF_8));
        }
        return detail;
    }

    @Override
    @Transactional
    public boolean addIcdPath(CsIcdPathParam param) {
        CsIcdPathParam checkedParam = requireParam(param);
        LocalDateTime now = LocalDateTime.now();
        CsIcdPathPO icdPath = buildIcdPath(checkedParam, true);
        icdPath.setId(UUID.randomUUID().toString().replace("-", ""));
        fillSelfReferenceForStandardIcd(icdPath);
        icdPath.setState(STATE_NORMAL);
        icdPath.setCreateBy(currentUserId());
        icdPath.setCreateTime(now);
        icdPath.setUpdateBy(currentUserId());
        icdPath.setUpdateTime(now);
        return csIcdPathMapper.insert(icdPath) > 0;
    }

    @Override
    @Transactional
    public boolean updateIcdPath(CsIcdPathParam.UpdateParam param) {
        CsIcdPathParam.UpdateParam checkedParam = requireUpdateParam(param);
        requireIcdPath(checkedParam.getId());
        CsIcdPathPO icdPath = buildIcdPath(checkedParam, false);
        icdPath.setId(checkedParam.getId());
        icdPath.setUpdateBy(currentUserId());
        icdPath.setUpdateTime(LocalDateTime.now());
        return csIcdPathMapper.updateById(icdPath) > 0;
    }

    @Override
    @Transactional
    public boolean activateIcdPath(String icdId) {
        CsIcdPathPO targetIcdPath = requireIcdPath(icdId);
        LocalDateTime now = LocalDateTime.now();
        String currentUserId = currentUserId();

        csIcdPathMapper.update(null, new LambdaUpdateWrapper<CsIcdPathPO>()
                .set(CsIcdPathPO::getType, ICD_TYPE_MANUAL_NON_STANDARD)
                .set(CsIcdPathPO::getUpdateBy, currentUserId)
                .set(CsIcdPathPO::getUpdateTime, now)
                .eq(CsIcdPathPO::getState, STATE_NORMAL)
                .eq(CsIcdPathPO::getType, ICD_TYPE_MANUAL_STANDARD));

        csIcdPathMapper.update(null, new LambdaUpdateWrapper<CsIcdPathPO>()
                .set(CsIcdPathPO::getType, ICD_TYPE_UPSTREAM_NON_STANDARD)
                .set(CsIcdPathPO::getUpdateBy, currentUserId)
                .set(CsIcdPathPO::getUpdateTime, now)
                .eq(CsIcdPathPO::getState, STATE_NORMAL)
                .eq(CsIcdPathPO::getType, ICD_TYPE_UPSTREAM_STANDARD));

        CsIcdPathPO activeIcdPath = new CsIcdPathPO();
        activeIcdPath.setType(resolveStandardType(targetIcdPath.getType()));
        activeIcdPath.setUpdateBy(currentUserId);
        activeIcdPath.setUpdateTime(now);
        return csIcdPathMapper.update(activeIcdPath, new LambdaUpdateWrapper<CsIcdPathPO>()
                .eq(CsIcdPathPO::getId, targetIcdPath.getId())
                .eq(CsIcdPathPO::getState, STATE_NORMAL)) > 0;
    }

    @Override
    @Transactional
    public boolean deleteIcdPath(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new IllegalArgumentException("ICD记录ID不能为空");
        }
        CsIcdPathPO icdPath = new CsIcdPathPO();
        icdPath.setState(STATE_DELETED);
        icdPath.setUpdateBy(currentUserId());
        icdPath.setUpdateTime(LocalDateTime.now());
        return csIcdPathMapper.update(icdPath, new LambdaUpdateWrapper<CsIcdPathPO>()
                .in(CsIcdPathPO::getId, ids)
                .eq(CsIcdPathPO::getState, STATE_NORMAL)) > 0;
    }

    @Override
    @Transactional
    public boolean saveIcdCheckResult(String icdId, IcdCheckResultSaveParam param) {
        if (param == null) {
            throw new IllegalArgumentException("ICD校验结果不能为空");
        }
        CsIcdPathPO icdPath = requireIcdPath(icdId);
        CsIcdPathPO referenceIcd = requireReferenceIcd(icdPath.getReferenceIcdId());
        icdPath.setJsonStr(trimToNull(param.getMappingJson()));
        icdPath.setXmlStr(trimToNull(param.getXml()));
        icdPath.setResult(normalizeResult(param.getResult()));
        icdPath.setMsg(param.getMsg());
        icdPath.setReferenceIcdId(referenceIcd.getId());
        if (param.getIcdDocument() != null) {
            icdPath.setIcdContent(serializeIcdDocument(param));
        } else if (param.getIcdContent() != null && param.getIcdContent().length > 0) {
            icdPath.setIcdContent(param.getIcdContent());
        }
        icdPath.setUpdateBy(currentUserId());
        icdPath.setUpdateTime(LocalDateTime.now());
        return csIcdPathMapper.updateById(icdPath) > 0;
    }

    private byte[] serializeIcdDocument(IcdCheckResultSaveParam param) {
        try {
            return objectMapper.writeValueAsBytes(param.getIcdDocument());
        } catch (JsonProcessingException ex) {
            throw new IllegalArgumentException("ICD解析记录序列化失败：" + ex.getMessage(), ex);
        }
    }

    private CsIcdPathPO buildIcdPath(CsIcdPathParam param, boolean useDefaultType) {
        CsIcdPathPO icdPath = new CsIcdPathPO();
        icdPath.setName(requireText(param.getName(), "ICD名称不能为空"));
        icdPath.setIcdContent(param.getIcdContent());
        icdPath.setAngle(param.getAngle());
        icdPath.setUsePhaseIndex(param.getUsePhaseIndex());
        icdPath.setType(useDefaultType ? resolveIcdType(param.getType()) : param.getType());
        icdPath.setReferenceIcdId(trimToNull(param.getReferenceIcdId()));
        return icdPath;
    }

    /**
     * 新增 ICD 记录未显式传类型时，默认归类为手动录入的非标准 ICD。
     */
    private Integer resolveIcdType(Integer type) {
        return type == null ? ICD_TYPE_MANUAL_NON_STANDARD : type;
    }

    /**
     * 标准 ICD 新增时如果未传参照 ICD，则默认以自身作为参照来源。
     */
    private void fillSelfReferenceForStandardIcd(CsIcdPathPO icdPath) {
        if (icdPath == null || !isStandardType(icdPath.getType()) || !isBlank(icdPath.getReferenceIcdId())) {
            return;
        }
        icdPath.setReferenceIcdId(icdPath.getId());
    }

    private boolean isStandardType(Integer type) {
        return Integer.valueOf(ICD_TYPE_MANUAL_STANDARD).equals(type)
                || Integer.valueOf(ICD_TYPE_UPSTREAM_STANDARD).equals(type);
    }

    /**
     * 激活标准 ICD 时保留记录来源：手动录入升为 1，上游解析传递升为 3。
     */
    private Integer resolveStandardType(Integer type) {
        if (Integer.valueOf(ICD_TYPE_UPSTREAM_STANDARD).equals(type)
                || Integer.valueOf(ICD_TYPE_UPSTREAM_NON_STANDARD).equals(type)) {
            return ICD_TYPE_UPSTREAM_STANDARD;
        }
        return ICD_TYPE_MANUAL_STANDARD;
    }

    private CsIcdPathParam requireParam(CsIcdPathParam param) {
        if (param == null) {
            throw new IllegalArgumentException("ICD记录参数不能为空");
        }
        return param;
    }

    private CsIcdPathParam.UpdateParam requireUpdateParam(CsIcdPathParam.UpdateParam param) {
        if (param == null) {
            throw new IllegalArgumentException("ICD记录参数不能为空");
        }
        requireText(param.getId(), "ICD记录ID不能为空");
        return param;
    }

    private CsIcdPathPO requireIcdPath(String icdId) {
        String id = requireText(icdId, "ICD记录ID不能为空");
        CsIcdPathPO icdPath = csIcdPathMapper.selectById(id);
        if (icdPath == null || !Integer.valueOf(STATE_NORMAL).equals(icdPath.getState())) {
            throw new IllegalArgumentException("ICD记录不存在或已删除");
        }
        return icdPath;
    }

    /**
     * ICD 校验保存时以当前记录绑定的 Reference_Icd_Id 作为参照来源。
     */
    private CsIcdPathPO requireReferenceIcd(String referenceIcdId) {
        String id = requireText(referenceIcdId, "未配置参照ICD，无法保存校验结果");
        CsIcdPathPO referenceIcd = csIcdPathMapper.selectById(id);
        if (referenceIcd == null || !Integer.valueOf(STATE_NORMAL).equals(referenceIcd.getState())) {
            throw new IllegalArgumentException("参照ICD不存在或已删除，无法保存校验结果");
        }
        return referenceIcd;
    }

    private Integer normalizeResult(Integer result) {
        if (result == null) {
            throw new IllegalArgumentException("校验结论不能为空");
        }
        if (result != 0 && result != 1) {
            throw new IllegalArgumentException("校验结论只能是0或1");
        }
        return result;
    }

    private String requireText(String value, String message) {
        String text = trimToNull(value);
        if (text == null) {
            throw new IllegalArgumentException(message);
        }
        return text;
    }

    private String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String text = value.trim();
        return text.isEmpty() ? null : text;
    }

    private boolean isBlank(String value) {
        return trimToNull(value) == null;
    }

    private String currentUserId() {
        try {
            String userId = RequestUtil.getUserId();
            return isBlank(userId) ? "未知用户" : userId;
        } catch (Exception ex) {
            return "未知用户";
        }
    }
}
