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

import com.njcn.gather.icd.mapping.component.DefaultTemplateLoader;
import com.njcn.gather.icd.mapping.component.IcdParserService;
import com.njcn.gather.icd.mapping.component.IcdToXmlMappingService;
import com.njcn.gather.icd.mapping.component.IndexAnalysisService;
import com.njcn.gather.icd.mapping.component.IndexValidationService;
import com.njcn.gather.icd.mapping.component.JsonToXmlConversionService;
import com.njcn.gather.icd.mapping.component.MappingDocumentSerializer;
import com.njcn.gather.icd.mapping.component.MappingGenerationService;
import com.njcn.gather.icd.mapping.component.RuleBasedXmlMappingService;
import com.njcn.gather.icd.mapping.pojo.bo.IcdToXmlGenerateResult;
import com.njcn.gather.icd.mapping.pojo.bo.analysis.IndexAnalysis;
import com.njcn.gather.icd.mapping.pojo.bo.analysis.ValidationResult;
import com.njcn.gather.icd.mapping.pojo.bo.icd.IcdDocument;
import com.njcn.gather.icd.mapping.pojo.bo.mapping.MappingDocument;
import com.njcn.gather.icd.mapping.pojo.bo.template.DefaultTemplate;
import com.njcn.gather.icd.mapping.pojo.dto.IcdToXmlGenerateCommand;
import com.njcn.gather.icd.mapping.pojo.dto.IndexSelectionGroupCommand;
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * ICD/XML 生成任务编排服务。
 *
 * 负责组织 ICD 到 XML、MMS JSON 到 XML 两类转换链路，避免 Controller 关注模板、规则和异常处理细节。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IcdToXmlTaskAppService {

    /** ICD 转 XML 阶段名称。 */
    private static final String ICD_TO_XML_TASK_NAME = "ICD 转 XML";
    /** JSON 转 XML 阶段名称。 */
    private static final String JSON_TO_XML_TASK_NAME = "XML 生成";
    /** 缺少索引绑定提示。 */
    private static final String INDEX_SELECTION_MISSING_MESSAGE = "索引配置缺失或不合法，请根据候选信息完成标签与数字索引的绑定后重新提交";
    /** 映射生成成功提示。 */
    private static final String MAPPING_GENERATE_SUCCESS_MESSAGE = "映射生成成功";
    /** XML 生成成功提示。 */
    private static final String XML_GENERATE_SUCCESS_MESSAGE = "XML 生成成功";
    /** 空 JSON 提示。 */
    private static final String MAPPING_JSON_EMPTY_MESSAGE = "MMS映射JSON不能为空";
    /** 缺少默认 XML 模板提示。 */
    private static final String DEFAULT_XML_MISSING_MESSAGE = "缺少默认xml配置文件";
    /** 缺少默认规则文件提示。 */
    private static final String DEFAULT_RULE_MISSING_MESSAGE = "缺少默认规则配置文件";

    /** ICD/SCL 文件解析服务。 */
    private final IcdParserService icdParserService;
    /** DefaultCfg.txt 默认模板加载器。 */
    private final DefaultTemplateLoader defaultTemplateLoader;
    /** 根据 ICD 和模板生成前端可选索引候选。 */
    private final IndexAnalysisService indexAnalysisService;
    /** 校验前端回传的标签与 lnInst 绑定关系。 */
    private final IndexValidationService indexValidationService;
    /** 根据有效绑定关系生成最终 MappingDocument。 */
    private final MappingGenerationService mappingGenerationService;
    /** XML 模板和规则文件加载服务。 */
    private final RuleBasedXmlMappingService ruleBasedXmlMappingService;
    /** 将 MappingDocument 序列化为 JSON。 */
    private final MappingDocumentSerializer mappingDocumentSerializer;
    /** 根据索引绑定关系重建 XML 规则中的实例索引。 */
    private final IcdToXmlMappingService icdToXmlMappingService;
    /** 将 MMS JSON 中间态转换为 XML 内容。 */
    private final JsonToXmlConversionService jsonToXmlConversionService;

    /**
     * 直接从 JSON 字符串生成 XML 内容。
     * 
     * @param mappingJson MMS 映射 JSON 字符串（由 getIcdMmsJson 接口返回）
     * @param configType 配置文件类型：1-读取 Jiangsuconfig2.xml，2-读取 Jiangsuconfig1.xml，空或错误时默认为 1
     * @return XML 生成结果
     */
    public IcdToXmlGenerateResult generateXmlFromJson(String mappingJson, Integer configType) {
        return executeTask(JSON_TO_XML_TASK_NAME, result -> {
            if (isBlank(mappingJson)) {
                markFailed(result, JSON_TO_XML_TASK_NAME, MAPPING_JSON_EMPTY_MESSAGE);
                return;
            }

            fillXmlContent(result, mappingJson, loadXmlResources(configType),configType);
            result.setStatus(GenerateStatus.SUCCESS);
            result.setMessage(XML_GENERATE_SUCCESS_MESSAGE);
        });
    }

    /**
     * 统一包装任务执行结果，避免每个入口重复编写异常兜底逻辑。
     */
    private IcdToXmlGenerateResult executeTask(String taskName, IcdToXmlTaskAction action) {
        IcdToXmlGenerateResult result = new IcdToXmlGenerateResult();
        try {
            action.execute(result);
        } catch (Exception ex) {
            handleTaskFailure(result, taskName, ex);
        }
        return result;
    }

    /**
     * 解析 ICD 并补齐模板、索引候选上下文。
     */
    private IcdToXmlTaskContext buildTaskContext(IcdToXmlGenerateCommand command, IcdToXmlGenerateResult result) {
        IcdDocument icdDocument = icdParserService.parse(command.getFileBytes(), command.getFileName());
        fillIcdSummary(result, icdDocument);

        DefaultTemplate template = loadTemplate(result);
        IndexAnalysis indexAnalysis = analyzeIndexCandidates(icdDocument, template, result);
        result.setIndexAnalysis(indexAnalysis);
        return new IcdToXmlTaskContext(icdDocument, template, indexAnalysis);
    }

    /**
     * 加载并校验默认模板。
     */
    private DefaultTemplate loadTemplate(IcdToXmlGenerateResult result) {
        DefaultTemplate template = defaultTemplateLoader.load();
        result.getProblems().addAll(template.verify());
        return template;
    }

    /**
     * 分析 ICD 对应的索引候选。
     */
    private IndexAnalysis analyzeIndexCandidates(IcdDocument icdDocument,
                                                 DefaultTemplate template,
                                                 IcdToXmlGenerateResult result) {
        IndexAnalysis indexAnalysis = indexAnalysisService.analyze(icdDocument, template);
        result.getProblems().addAll(indexAnalysis.getProblems());
        return indexAnalysis;
    }

    /**
     * 加载 XML 模板和规则文件。
     */
    private XmlResourceContext loadXmlResources() throws Exception {
        return loadXmlResources(2);
    }

    private XmlResourceContext loadXmlResources(Integer configType) throws Exception {
        InputStream templateStream = ruleBasedXmlMappingService.loadDefaultXmlFile(configType);
        if (templateStream == null) {
            throw new IllegalArgumentException(DEFAULT_XML_MISSING_MESSAGE);
        }

        List<InputStream> ruleStreams = ruleBasedXmlMappingService.loadDefaultRuleFile();
        if (ruleStreams == null) {
            throw new IllegalArgumentException(DEFAULT_RULE_MISSING_MESSAGE);
        }

        return new XmlResourceContext(templateStream, ruleStreams);
    }

    /**
     * 根据索引绑定关系刷新 XML 转换所需的实例索引。
     */
    private void bindIndexMapping(List<IndexSelectionGroupCommand> indexSelection) {
        IcdToXmlMappingService.IndexMappingConfig mappingConfig = icdToXmlMappingService.buildIndexMappingFromSelection(indexSelection);
        icdToXmlMappingService.setIndexMapping(mappingConfig);
    }

    /**
     * 将 MMS JSON 中间态转换为 XML 内容。
     */
    private void fillXmlContent(IcdToXmlGenerateResult result,
                                String mappingJson,
                                XmlResourceContext xmlResourceContext,
                                Integer configType) throws Exception {
        List<String> methodDescribeList = new ArrayList<>();
        String xmlContent = jsonToXmlConversionService.buildXmlContentFromJson(
                mappingJson,
                xmlResourceContext.templateStream,
                xmlResourceContext.ruleStreams,
                icdToXmlMappingService.getIndexMapping(),
                configType,
                methodDescribeList
        );
        result.setXmlContent(xmlContent);
        result.setMethodDescribe(String.join("\n", methodDescribeList));
    }

    /**
     * 回填响应公共信息。
     */
    private void fillIcdSummary(IcdToXmlGenerateResult result, IcdDocument icdDocument) {
        result.setIedName(icdDocument.getIedName());
        result.setLdInst(icdDocument.getLdInst());
    }

    /**
     * 标记当前仍需用户重新确认索引绑定。
     */
    private void markNeedIndexSelection(IcdToXmlGenerateResult result) {
        result.setStatus(GenerateStatus.NEED_INDEX_SELECTION);
        result.setMessage(INDEX_SELECTION_MISSING_MESSAGE);
    }

    /**
     * 标记可预期的业务失败。
     */
    private void markFailed(IcdToXmlGenerateResult result, String taskName, String errorMessage) {
        result.setStatus(GenerateStatus.FAILED);
        result.setMessage(taskName + "失败：" + errorMessage);
        result.getProblems().add(errorMessage);
    }

    /**
     * 统一处理任务异常，避免控制层再补失败分支。
     */
    private void handleTaskFailure(IcdToXmlGenerateResult result, String taskName, Exception ex) {
        log.error("{}失败", taskName, ex);
        String errorMessage = resolveErrorMessage(ex);
        markFailed(result, taskName, errorMessage);
    }

    private boolean isIndexSelectionEmpty(List<IndexSelectionGroupCommand> indexSelection) {
        return indexSelection == null || indexSelection.isEmpty();
    }

    private boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }

    private String resolveErrorMessage(Exception ex) {
        if (ex.getMessage() == null || ex.getMessage().trim().isEmpty()) {
            return ex.getClass().getSimpleName();
        }
        return ex.getMessage();
    }

    @FunctionalInterface
    private interface IcdToXmlTaskAction {
        void execute(IcdToXmlGenerateResult result) throws Exception;
    }

    /**
     * 供 ICD 转 XML 流程复用的编排上下文。
     */
    private static class IcdToXmlTaskContext {

        private final IcdDocument icdDocument;

        private final DefaultTemplate template;

        private final IndexAnalysis indexAnalysis;

        private IcdToXmlTaskContext(IcdDocument icdDocument, DefaultTemplate template, IndexAnalysis indexAnalysis) {
            this.icdDocument = icdDocument;
            this.template = template;
            this.indexAnalysis = indexAnalysis;
        }
    }

    /**
     * XML 转换所需的模板和规则资源。
     */
    private static class XmlResourceContext {

        private final InputStream templateStream;

        private final List<InputStream> ruleStreams;

        private XmlResourceContext(InputStream templateStream, List<InputStream> ruleStreams) {
            this.templateStream = templateStream;
            this.ruleStreams = ruleStreams;
        }
    }

}
