package com.njcn.gather.icd.mapping.controller;

import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.LogUtil;
import com.njcn.gather.icd.mapping.component.IcdToXmlResponseConverter;
import com.njcn.gather.icd.mapping.component.IcdConsistencyCheckService;
import com.njcn.gather.icd.mapping.component.IndexSelectionBuildService;
import com.njcn.gather.icd.mapping.component.MappingRequestConverter;
import com.njcn.gather.icd.mapping.component.MappingResponseConverter;
import com.njcn.gather.icd.mapping.pojo.bo.GenerateMappingResult;
import com.njcn.gather.icd.mapping.pojo.bo.IcdToXmlGenerateResult;
import com.njcn.gather.icd.mapping.pojo.dto.GenerateFromIcdCommand;
import com.njcn.gather.icd.mapping.pojo.param.BuildIndexSelectionRequest;
import com.njcn.gather.icd.mapping.pojo.param.GenerateMappingFromIcdRequest;
import com.njcn.gather.icd.mapping.pojo.param.IcdConsistencyCheckRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexCandidateRequest;
import com.njcn.gather.icd.mapping.pojo.param.JsonToXmlRequest;
import com.njcn.gather.icd.mapping.pojo.param.SubmitIndexSelectionRequest;
import com.njcn.gather.icd.mapping.pojo.vo.IcdConsistencyCheckResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IcdToXmlResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexConfirmGroupResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexSelectionGroupResponse;
import com.njcn.gather.icd.mapping.pojo.vo.MappingTaskResponse;
import com.njcn.gather.icd.mapping.service.MappingTaskService;
import com.njcn.gather.icd.mapping.service.impl.IcdToXmlTaskAppService;
import com.njcn.gather.icd.mapping.utils.DateUtils;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.HttpResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * ICD 映射接口入口。
 */
@Slf4j
@Api(tags = "ICD 映射")
@RestController
@RequestMapping("/api/mms-mapping")
@RequiredArgsConstructor
public class MappingController extends BaseController {

    /** 映射任务编排服务，负责从 ICD 解析到映射生成的完整链路。 */
    private final MappingTaskService mappingTaskService;

    /** 请求参数转换器，将接口入参转换为应用层命令。 */
    private final MappingRequestConverter requestConverter;

    /** 响应转换器，按接口阶段裁剪最小返回字段。 */
    private final MappingResponseConverter responseConverter;

    /** 请求参数转换器，将接口入参转换为应用层命令。 */
    private final  IcdToXmlResponseConverter icdResponseConverter;

    /** 响应转换器，按接口阶段裁剪最小返回字段。 */
    private final IcdToXmlTaskAppService  icdToXmlTaskAppService;

    /** ICD 结构确认弹窗结果组装服务。 */
    private final IndexSelectionBuildService indexSelectionBuildService;

    /** ICD 映射 JSON 一致性校验服务。 */
    private final IcdConsistencyCheckService icdConsistencyCheckService;

    /**
     * 上传 ICD 文件，返回候选结果和可编辑的 ICD 解析结果。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("上传 ICD 文件并生成索引候选")
    @ApiImplicitParam(name = "icdFile", value = "ICD 文件", required = true, dataType = "__file", paramType = "form")
    @PostMapping(value = "/get-icd", consumes = {"multipart/form-data"})
    public MappingTaskResponse getICD(@RequestPart("icdFile") MultipartFile icdFile) {
        String methodDescribe = getMethodDescribe("getICD");
        LogUtil.njcnDebug(log, "{}，开始解析 ICD 文件并生成索引候选，fileName={}", methodDescribe, DateUtils.resolveFileName(icdFile));
        GenerateFromIcdCommand command = requestConverter.toCommand(icdFile);
        GenerateMappingResult result = mappingTaskService.getICD(command);
        return responseConverter.fromCandidateResult(result);
    }

    /**
     * 根据前端确认后的索引绑定关系生成 MMS JSON。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("获取 MMS JSON")
    @ApiImplicitParam(name = "request", value = "索引确认后生成 MMS JSON 参数", required = true, dataType = "SubmitIndexSelectionRequest")
    @PostMapping("/get-mms-json")
    public MappingTaskResponse getMmsJson(@Validated @RequestBody SubmitIndexSelectionRequest request) {
        String methodDescribe = getMethodDescribe("getMmsJson");
        LogUtil.njcnDebug(log, "{}，开始生成 MMS JSON，indexSelectionCount={}",
                methodDescribe, DateUtils.resolveSelectionCount(request == null ? null : request.getIndexSelection()));
        GenerateFromIcdCommand command = requestConverter.toCommand(request);
        GenerateMappingResult result = mappingTaskService.getMmsJson(command);
        return responseConverter.fromSubmitResult(result);
    }

    /**
     * 上传 ICD 后直接串联候选生成和索引提交，统一返回正式提交阶段结果。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("上传 ICD 后直接获取 MMS JSON")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "icdFile", value = "ICD 文件", required = true, dataType = "__file", paramType = "form"),
            @ApiImplicitParam(name = "request", value = "上传 ICD 后直接生成映射参数", required = true, dataType = "GenerateMappingFromIcdRequest", paramType = "form")
    })
    @PostMapping(value = "/get-icd-mms-json", consumes = {"multipart/form-data"})
    public MappingTaskResponse getIcdMmsJson(@RequestPart("icdFile") MultipartFile icdFile,
                                             @Validated @RequestPart("request") GenerateMappingFromIcdRequest request) {
        String methodDescribe = getMethodDescribe("getIcdMmsJson");
        LogUtil.njcnDebug(log, "{}，开始获取 ICD MMS JSON，fileName={}, indexSelectionCount={}",
                methodDescribe, DateUtils.resolveFileName(icdFile),
                DateUtils.resolveSelectionCount(request == null ? null : request.getIndexSelection()));
        GenerateFromIcdCommand command = requestConverter.toCommand(icdFile, request);
        GenerateMappingResult result = mappingTaskService.getIcdMmsJson(command);
        return responseConverter.fromSubmitResult(result);
    }

    /**
     * 根据页面回传的 indexCandidates 生成弹窗确认模型。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("根据 indexCandidates 生成确认数据")
    @ApiImplicitParam(name = "indexCandidates", value = "索引候选分组列表", required = true, dataType = "List")
    @PostMapping("/build-index-confirm-data")
    public HttpResult<List<IndexConfirmGroupResponse>> buildIndexConfirmData(@RequestBody List<IndexCandidateRequest> indexCandidates) {
        String methodDescribe = getMethodDescribe("buildIndexConfirmData");
        LogUtil.njcnDebug(log, "{}，开始根据 indexCandidates 生成确认数据，candidateCount={}",
                methodDescribe, indexCandidates == null ? 0 : indexCandidates.size());
        List<IndexConfirmGroupResponse> result = indexSelectionBuildService.buildConfirmData(indexCandidates);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
    }

    /**
     * 根据前端确认后的结果生成最终 indexSelection。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("根据确认结果生成 indexSelection")
    @ApiImplicitParam(name = "request", value = "根据确认结果生成 indexSelection 参数", required = true, dataType = "BuildIndexSelectionRequest")
    @PostMapping("/build-index-selection")
    public HttpResult<List<IndexSelectionGroupResponse>> buildIndexSelection(@RequestBody BuildIndexSelectionRequest request) {
        String methodDescribe = getMethodDescribe("buildIndexSelection");
        LogUtil.njcnDebug(log, "{}，开始根据确认结果生成 indexSelection，confirmGroupCount={}, confirmedGroupCount={}",
                methodDescribe,
                request == null || request.getConfirmData() == null ? 0 : request.getConfirmData().size(),
                request == null || request.getConfirmedData() == null ? 0 : request.getConfirmedData().size());
        List<IndexSelectionGroupResponse> result = indexSelectionBuildService.buildIndexSelection(request);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
    }

    /**
     * 直接将 MMS JSON 转换为 XML 内容。
     * 适用于已经通过 getIcdMmsJson 获得 JSON 后，单独进行 XML 转换的场景。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("MMS JSON 转 XML")
    @ApiImplicitParam(name = "request", value = "MMS JSON 转 XML 参数", required = true, dataType = "JsonToXmlRequest")
    @PostMapping("/get-xml-from-json")
    public IcdToXmlResponse getXmlFromJson(@Validated @RequestPart("request") JsonToXmlRequest request) {
        String methodDescribe = getMethodDescribe("getXmlFromJson") + "，开始将 MMS JSON 转换为 XML";

        Integer configType = request == null ? null : request.getConfigType();
        if (configType == null || (configType != 1 && configType != 2)) {
            configType = 2;
        }

        IcdToXmlGenerateResult result =
            icdToXmlTaskAppService.generateXmlFromJson(request == null ? null : request.getMappingJson(), configType);
        if (result.getMethodDescribe() != null && !result.getMethodDescribe().trim().isEmpty()) {
            methodDescribe = methodDescribe + "\n" + result.getMethodDescribe();
        }

        IcdToXmlResponse response = icdResponseConverter.fromResult(result);
        response.setMethodDescribe(methodDescribe);
        return response;
    }

    /**
     * 将待校验 MMS 映射 JSON 与标准 MMS 映射 JSON 做 ICD 一致性校验。
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("ICD 一致性校验")
    @ApiImplicitParam(name = "request", value = "ICD 一致性校验参数", required = true, dataType = "IcdConsistencyCheckRequest")
    @PostMapping("/check-icd-json-consistency")
    public IcdConsistencyCheckResponse checkIcdJsonConsistency(@Validated @RequestBody IcdConsistencyCheckRequest request) {
        String methodDescribe = getMethodDescribe("checkIcdJsonConsistency");
        LogUtil.njcnDebug(log, "{}，开始执行 ICD 一致性校验", methodDescribe);
        return icdConsistencyCheckService.check(request);
    }

}
