package com.xdap.self_development.service.impl;

import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.self_development.common.BusinessDatabase;
import com.xdap.self_development.common.MyPageResult;
import com.xdap.self_development.controller.form.ParameterForm;
import com.xdap.self_development.controller.form.ParameterPageForm;
import com.xdap.self_development.controller.form.UpdateParameterForm;
import com.xdap.self_development.domain.enums.ParameterOperationEnum;
import com.xdap.self_development.domain.pojo.ParameterPojo;
import com.xdap.self_development.domain.pojo.RevisionRecordPojo;
import com.xdap.self_development.domain.pojo.TemplateAndParameterPojo;
import com.xdap.self_development.domain.pojo.TemplatePojo;
import com.xdap.self_development.domain.view.TemplateInfoView;
import com.xdap.self_development.exception.CommonException;
import com.xdap.self_development.service.ModelRoleService;
import com.xdap.self_development.service.ParameterService;
import com.xdap.self_development.utils.FormulaValidatorUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 参数服务实现类
 *
 * @version 1.0
 * @since 2025
 */
@Service
public class ParameterServiceImpl implements ParameterService {
	@Resource
	private BusinessDatabase bd;
	@Resource
	private ParameterService myself;
	@Resource
	private ModelRoleService modelRoleService;

	/**
	 * 根据条件获取参数
	 * 根据页面表单条件查询参数信息
	 *
	 * @param form 参数页面表单
	 * @return 参数POJO分页结果
	 */
	@Override
	public MyPageResult<ParameterPojo> getParameterByCondition(ParameterPageForm form) {
		TemplatePojo template = bd.getBusinessDatabase()
				.rowid("id", form.getTemplateRowId())
				.doQueryFirst(TemplatePojo.class);

		if (template == null) {
			throw new CommonException("模板未找到");
		}
		PageQueryResult<ParameterPojo> parameterPageQueryResult = bd.getBusinessDatabase()
				.viewQueryMode(true)
				.view("selectParametersByTId")
				.setVar("templateId", template.getId())
				.like("parameter_name", form.getParameterName())
				.like("parts_name", form.getPartsName())
				.like("parameter_type", form.getParameterType())
				.doPageQuery(form.getPageNumber(), form.getPageSize(), ParameterPojo.class);
		MyPageResult<ParameterPojo> myPageResult = new MyPageResult<>();
		myPageResult.setCount(parameterPageQueryResult.getCount());
		myPageResult.setResult(parameterPageQueryResult.getResult());
		myPageResult.setStatus(template.getStatus());
		return myPageResult;
	}

	/**
	 * 维护参数
	 * 根据表单信息维护参数信息
	 *
	 * @param form 更新参数表单
	 * @return 模板信息视图
	 */
	@Override
	@Transactional
	public TemplateInfoView maintenanceParameters(UpdateParameterForm form) {
		// 公式格式检查
		for (ParameterForm parameter : form.getParameterForms()) {
			if (parameter.getOperation() == null || parameter.getOperation().isEmpty()) {
				continue;
			}

			if ("数据平台手工录入".equals(parameter.getParameterSource()) && (parameter.getDepartment() == null || parameter.getDepartment().isEmpty())) {
				throw new CommonException(String.format("参数'%s'部门不能为空", parameter.getParameterName()));
			}
			if (parameter.getPartsName() == null || parameter.getPartsName().isEmpty()) {
				parameter.setPartsName("/");
			}

			if (Objects.equals(parameter.getParameterSource(), "公式计算")) {
				Map<String, Object> validationResult = FormulaValidatorUtils.validateFormulaDetailed(
						parameter.getNumberOrFormula());
				if (!(boolean) validationResult.get("isValid")) {
					String errorMsg = String.format("参数 '%s' 公式格式错误: %s",
							parameter.getParameterName(),
							validationResult.get("errorMessage"));
					throw new CommonException(errorMsg);
				}
			}
		}
		// 获取基准模板和最新模板
		TemplateBenchmark benchmark = myself.getTemplateBenchmark(form.getTemplateRowId());
		// 校验模板状态
		myself.validateTemplateStatus(benchmark);
		// 创建/复用新版本模板
		TemplatePojo newVersionTemplate = myself.createOrReuseNewTemplate(benchmark, form.getUserId());
		// 处理参数变更
		ParameterProcessingResult processingResult = myself.processParameters(
				form.getParameterForms(),
				benchmark.getParameters(),
				benchmark.getBaseTemplate(),
				newVersionTemplate,
				form.getUserId(),
				Objects.equals(newVersionTemplate.getId(), benchmark.getBaseTemplate().getId())
		);

		// 保存所有数据
		myself.saveAllData(benchmark.getBaseTemplate(), newVersionTemplate, processingResult);

		TemplateInfoView result = new TemplateInfoView();
		result.setTemplateRowId(newVersionTemplate.getRowId());
		result.setVersion(newVersionTemplate.getVersion());
		result.setTemplateId(newVersionTemplate.getId());
		return result;
	}

	/**
	 * 校验模板状态
	 * 校验模板的当前状态是否允许修改
	 *
	 * @param benchmark 模板基准信息
	 * @return void
	 */
    @Override
	public void validateTemplateStatus(TemplateBenchmark benchmark) {
		// 当前修改的模板不为最新版
		if (!Objects.equals(benchmark.getLastTemplate().getId(), benchmark.getBaseTemplate().getId())) {
			throw new CommonException("该模板不可修改，请修改最新版本");
		}

		// 校验模板状态（仅允许草稿/已发布）
		String status = benchmark.getBaseTemplate().getStatus();
		if (!"DRAFT".equals(status) && !"COMPLETE".equals(status)) {
			throw new CommonException("该状态的模板不可修改，仅支持草稿/已发布状态");
		}

		// 同名模板审核中不可修改
		List<TemplatePojo> templates = bd.getBusinessDatabase()
				.eq("template_name", benchmark.getBaseTemplate().getTemplateName())
				.orderBy("version", "asc").doQuery(TemplatePojo.class);
		boolean approving = templates.stream().map(TemplatePojo::getStatus)
				.collect(Collectors.toList()).contains("APPROVING");
		if (approving) {
			throw new CommonException("同名模板已在审核中,暂时不能修改参数");
		}
	}

	/**
	 * 创建/复用新版本模板
	 * 根据基准信息和用户ID创建或复用新版本模板
	 *
	 * @param benchmark 模板基准信息
	 * @param userId    用户ID
	 * @return 模板POJO
	 */
    @Override
    @Transactional
	public TemplatePojo createOrReuseNewTemplate(TemplateBenchmark benchmark, String userId) {
		TemplatePojo baseTemplate = benchmark.getBaseTemplate();
		// 草稿状态复用原模板，已发布创建新版本
		if ("DRAFT".equals(baseTemplate.getStatus())) {
			return baseTemplate;
		} else {
			TemplatePojo newTemplate = new TemplatePojo(
					benchmark.getLastTemplate().getTemplateName(),
					calculateNextVersion(benchmark.getLastTemplate().getVersion()),
					"DRAFT",
					Timestamp.valueOf(LocalDateTime.now()),
					null,
					userId,
					baseTemplate.getOrderNum(),
					0
			);
            newTemplate.setId(UUID.randomUUID().toString());
			return newTemplate;
		}
	}

	/**
	 * 获取模板基准
	 * 根据模板行ID获取模板基准信息
	 *
	 * @param templateRowId 模板行ID
	 * @return 模板基准信息
	 */
    @Override
	public TemplateBenchmark getTemplateBenchmark(String templateRowId) {
		// 基准模板（用户选择的要比较的版本）
		TemplatePojo baseTemplate = bd.getBusinessDatabase()
				.rowid("id", templateRowId)
				.doQueryFirst(TemplatePojo.class);

		if (baseTemplate == null) {
			throw new IllegalArgumentException("未找到对应的模板，ID: " + templateRowId);
		}

		// 最新版本模板
		TemplatePojo lastTemplate = bd.getBusinessDatabase()
				.eq("template_name", baseTemplate.getTemplateName())
				.orderBy("version", "desc")
				.doQueryFirst(TemplatePojo.class);

		if (lastTemplate == null) {
			throw new IllegalStateException("未找到模板的最新版本: " + baseTemplate.getTemplateName());
		}

		// 基准模板的参数
		List<ParameterPojo> parameters = bd.getBusinessDatabase()
				.viewQueryMode(true)
				.view("selectParametersByTId")
				.setVar("templateId", baseTemplate.getId())
				.doQuery(ParameterPojo.class);

		return new TemplateBenchmark(baseTemplate, lastTemplate, parameters);
	}


	/**
	 * 模板基准信息封装类
	 */
	@Data
	@AllArgsConstructor
	public static class TemplateBenchmark {
		private final TemplatePojo baseTemplate;
		private final TemplatePojo lastTemplate;
		private final List<ParameterPojo> parameters;
	}


	/**
	 * 参数处理结果封装类
	 */
	@Data
	@AllArgsConstructor
	public static class ParameterProcessingResult {
		private final List<ParameterPojo> newParameters;
		private final List<RevisionRecordPojo> revisionRecords;
	}

	/**
	 * 计算下一个版本号
	 * 根据当前版本号计算下一个版本号
	 *
	 * @param currentVersion 当前版本号
	 * @return 下一个版本号
	 */
	private Integer calculateNextVersion(Integer currentVersion) {
		try {
			return currentVersion + 1;
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException("版本号格式错误: " + currentVersion, e);
		}
	}

	/**
	 * 处理参数
	 * 根据表单和现有参数处理参数变更
	 *
	 * @param parameterForms      参数表单列表
	 * @param existingParameters  现有参数列表
	 * @param baseTemplate        基础模板
	 * @param newTemplate         新模板
	 * @param userId              用户ID
	 * @param isLastComplete      是否最后完成
	 * @return 参数处理结果
	 */
    @Override
	public ParameterProcessingResult processParameters(
            List<ParameterForm> parameterForms,
            List<ParameterPojo> existingParameters,
            TemplatePojo baseTemplate,
            TemplatePojo newTemplate,
			String userId,
			boolean isLastComplete
	) {
		Map<String, ParameterPojo> parameterMap = existingParameters.stream()
				.collect(Collectors.toMap(ParameterPojo::getId, param -> param, (k1, k2) -> {
					throw new IllegalStateException("发现重复的参数ID: " + k1);
				}));

		List<ParameterPojo> newParameters = new ArrayList<>();
		List<RevisionRecordPojo> revisionRecords = new ArrayList<>();

		// 处理模板部分参数
		for (ParameterForm parameterForm : parameterForms) {
			if (parameterForm.getOperation() == null) {
				parameterForm.setOperation("");
			}
			ParameterOperationEnum operation = ParameterOperationEnum.fromCode(parameterForm.getOperation());
			switch (operation) {
				case INSERT:
                    handleInsertOperation(parameterForm, newTemplate, newParameters, revisionRecords, userId);
					break;
				case UPDATE:
					handleUpdateOperation(parameterForm, parameterMap, newTemplate, newParameters, revisionRecords, baseTemplate, userId);
					break;
				case DELETE:
					handleDeleteOperation(parameterForm, parameterMap, newTemplate, revisionRecords, baseTemplate);
					break;
				case UNCHANGED:
					handleUnchangedOperation(parameterForm, parameterMap, newParameters, isLastComplete);
					break;
			}
		}

		// 处理模板剩余的参数
		List<ParameterPojo> unmatchedParameters = findUnmatchedParameters(parameterMap, parameterForms);
		// 未修改的参数也需要新增然后添加进新的参数列表中
		if (!isLastComplete && !unmatchedParameters.isEmpty()) {
			unmatchedParameters.forEach(parameter -> parameter.setId(null));
			bd.getBusinessDatabase().doBatchInsert(unmatchedParameters);
		}
		newParameters.addAll(unmatchedParameters);
		return new ParameterProcessingResult(newParameters, revisionRecords);
	}

	/**
	 * 处理新增参数
	 * 处理参数表单中的新增操作
	 *
	 * @param form              参数表单
	 * @param newTemplate       新模板
	 * @param newParameters     新参数列表
	 * @param revisionRecords   修订记录列表
	 * @param userId            用户ID
	 * @return void
	 */
    private void handleInsertOperation(
			ParameterForm form, TemplatePojo newTemplate,
			List<ParameterPojo> newParameters, List<RevisionRecordPojo> revisionRecords,
            String userId
    ) {
		ParameterPojo newParameter = new ParameterPojo();
		BeanUtils.copyProperties(form, newParameter);
		newParameter.setCreatedBy(userId);
		newParameter.setId(null);
        newParameter.setParameterNumber(String.valueOf(ThreadLocalRandom.current().nextInt(100000)));
        newParameter.setId(null);
		bd.getBusinessDatabase().doInsert(newParameter);
		newParameters.add(newParameter);
		revisionRecords.add(new RevisionRecordPojo(
				newTemplate.getTemplateName(),
				newTemplate.getVersion(),
				newParameter.getParameterNumber(),
				"新增参数",
				newTemplate.getId(),
				null,
				Timestamp.valueOf(LocalDateTime.now()),
				newParameter.getId(),
				newTemplate.getReturnNum()
		));
	}

	/**
	 * 处理更新参数
	 * 处理参数表单中的更新操作
	 *
	 * @param form            参数表单
	 * @param parameterMap    参数映射
	 * @param newTemplate     新模板
	 * @param newParameters   新参数列表
	 * @param revisionRecords 修订记录列表
	 * @param baseTemplate    基础模板
	 * @param userId          用户ID
	 * @return void
	 */
    private void handleUpdateOperation(
			ParameterForm form, Map<String, ParameterPojo> parameterMap,
			TemplatePojo newTemplate, List<ParameterPojo> newParameters,
			List<RevisionRecordPojo> revisionRecords, TemplatePojo baseTemplate,
			String userId
    ) {
		ParameterPojo originalParameter = parameterMap.get(form.getParameterId());

		if (originalParameter == null) {
			throw new IllegalArgumentException("未找到要更新的参数，编号: " + form.getParameterNumber());
		}

		ParameterPojo updatedParameter = new ParameterPojo();
		BeanUtils.copyProperties(form, updatedParameter);
		String detail = getParameterChange(originalParameter, updatedParameter);
		updatedParameter.setCreatedBy(userId);
		// 如果是原模板，就更新
		if (Objects.equals(baseTemplate.getId(), newTemplate.getId())) {
			updatedParameter.setId(originalParameter.getId());
			bd.getBusinessDatabase()
					.rowid("id", originalParameter.getRowId())
					.doUpdate(updatedParameter);
		}
		// 如果是新模板，就新增
		else {
			bd.getBusinessDatabase()
					.doInsert(updatedParameter);
		}
		newParameters.add(updatedParameter);
		revisionRecords.add(new RevisionRecordPojo(
				newTemplate.getTemplateName(),
				newTemplate.getVersion(),
				form.getParameterNumber(),
				detail,
				newTemplate.getId(),
				baseTemplate.getId(),
				Timestamp.valueOf(LocalDateTime.now()),
				updatedParameter.getId(),
				newTemplate.getReturnNum()
		));
	}

	/**
	 * 获取参数变更
	 * 获取两个参数对象之间的变更信息
	 *
	 * @param originalParameter 原始参数
	 * @param updatedParameter  更新后参数
	 * @return 参数变更信息
	 */
	private String getParameterChange(ParameterPojo originalParameter, ParameterPojo updatedParameter) {
        return handleParameterChange("参数名", originalParameter.getParameterName(), updatedParameter.getParameterName()) +
                handleParameterChange("参数类型", originalParameter.getParameterType(), updatedParameter.getParameterType()) +
                handleParameterChange("子系统", originalParameter.getSubsystemName(), updatedParameter.getSubsystemName()) +
                handleParameterChange("部件名", originalParameter.getPartsName(), updatedParameter.getPartsName()) +
                handleParameterChange("单位名", originalParameter.getUnit(), updatedParameter.getUnit()) +
                handleParameterChange("参数来源", originalParameter.getParameterSource(), updatedParameter.getParameterSource()) +
                handleParameterChange("公式或编号", originalParameter.getNumberOrFormula(), updatedParameter.getNumberOrFormula()) +
				handleParameterChange("部门名", originalParameter.getDepartment(), updatedParameter.getDepartment()) +
				handleParameterChange("是否为数值类型", originalParameter.getIsNumber(), updatedParameter.getIsNumber());
	}

	/**
	 * 处理参数变更
	 * 处理单个参数字段的变更信息
	 *
	 * @param name               参数名称
	 * @param originalParameter  原始参数值
	 * @param updatedParameter   更新后参数值
	 * @return 参数变更信息
	 */
	private String handleParameterChange(String name, String originalParameter, String updatedParameter) {
		StringBuilder sb = new StringBuilder();
		if ((originalParameter == null && (updatedParameter == null || updatedParameter.isEmpty()))) {
			return sb.toString();
		}
		if (!Objects.equals(originalParameter, updatedParameter)) {
			if (originalParameter == null || originalParameter.isEmpty()) {
				if (updatedParameter == null || updatedParameter.isEmpty()) {
					sb.append(name).append(": ").append("变更为空值").append("\n");
				} else {
					sb.append(name).append(": ").append("变更为: '").append(updatedParameter).append("' ").append("\n");
				}
			} else {
				if (updatedParameter == null || updatedParameter.isEmpty()) {
					sb.append(name).append(": '").append(originalParameter).append("' 变更为 空值").append("\n");
				} else {
					sb.append(name).append(": '").append(originalParameter).append("' 变更为 '").append(updatedParameter).append("'\n");
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 处理删除参数
	 * 处理参数表单中的删除操作
	 *
	 * @param form            参数表单
	 * @param parameterMap    参数映射
	 * @param newTemplate     新模板
	 * @param revisionRecords 修订记录列表
	 * @param baseTemplate    基础模板
	 * @return void
	 */
	private void handleDeleteOperation(
			ParameterForm form, Map<String, ParameterPojo> parameterMap,
			TemplatePojo newTemplate, List<RevisionRecordPojo> revisionRecords,
			TemplatePojo baseTemplate
	) {
		ParameterPojo deletedParameter = parameterMap.get(form.getParameterId());

		if (deletedParameter != null) {
			revisionRecords.add(new RevisionRecordPojo(
					newTemplate.getTemplateName(),
					newTemplate.getVersion(),
					form.getParameterNumber(),
					"删除参数",
					newTemplate.getId(),
					baseTemplate.getId(),
					Timestamp.valueOf(LocalDateTime.now()),
					deletedParameter.getId(),
					newTemplate.getReturnNum()
			));
		}
	}

	/**
	 * 处理未修改参数
	 * 处理参数表单中的未修改操作
	 *
	 * @param form            参数表单
	 * @param parameterMap    参数映射
	 * @param newParameters   新参数列表
	 * @param isLastComplete  是否最后完成
	 * @return void
	 */
	private void handleUnchangedOperation(
			ParameterForm form, Map<String, ParameterPojo> parameterMap,
			List<ParameterPojo> newParameters, boolean isLastComplete
	) {
		ParameterPojo unchangedParameter = parameterMap.get(form.getParameterId());
		if (unchangedParameter == null) {
			return;
		}
		// 未修改的参数也需要新增然后添加进新的参数列表中
		if (!isLastComplete) {
			unchangedParameter.setId(null);
			bd.getBusinessDatabase().doInsert(unchangedParameter);
		}
		newParameters.add(unchangedParameter);
	}

	/**
	 * 查找未匹配的参数
	 * 查找参数映射中未在参数表单中出现的参数
	 *
	 * @param parameterMap   参数映射
	 * @param parameterForms 参数表单列表
	 * @return 未匹配的参数列表
	 */
	public List<ParameterPojo> findUnmatchedParameters(
			Map<String, ParameterPojo> parameterMap,
			List<ParameterForm> parameterForms) {
		Set<String> formIds = parameterForms.stream()
				.map(ParameterForm::getParameterId)
				.filter(Objects::nonNull)
				.collect(Collectors.toSet());
		return parameterMap.entrySet().stream()
				.filter(entry -> !formIds.contains(entry.getKey()))
				.map(Map.Entry::getValue)
				.collect(Collectors.toList());
	}

	/**
	 * 保存所有数据
	 * 保存模板和参数处理结果的所有数据
	 *
	 * @param originalTemplate 原始模板
	 * @param newTemplate      新模板
	 * @param result           参数处理结果
	 * @return void
	 */
    @Override
    @Transactional
	public void saveAllData(TemplatePojo originalTemplate, TemplatePojo newTemplate, ParameterProcessingResult result) {
		List<String> parameterIds = bd.getBusinessDatabase()
				.eq("template_id", newTemplate.getId())
				.doQuery(TemplateAndParameterPojo.class).stream()
				.map(TemplateAndParameterPojo::getParameterId)
				.collect(Collectors.toList());

		// 如果是原模板
		if (Objects.equals(originalTemplate.getId(), newTemplate.getId())) {
			bd.getBusinessDatabase()
					.eq("template_id", originalTemplate.getId())
					.doDelete(TemplateAndParameterPojo.class);
			List<TemplateAndParameterPojo> templateAndParameters =
					result.getNewParameters().stream()
							.map(parameter -> createTemplateAndParameter(newTemplate.getId(), parameter.getId()))
							.collect(Collectors.toList());
			if (!templateAndParameters.isEmpty()) {
				bd.getBusinessDatabase().doBatchInsert(templateAndParameters);
			}
		}
		// 如果不是原模板
		else {
            bd.getBusinessDatabase().doInsert(newTemplate);
			List<TemplateAndParameterPojo> templateAndParameters =
					result.getNewParameters().stream()
							.filter(parameter -> !parameterIds.contains(parameter.getId()))
							.map(parameter -> createTemplateAndParameter(newTemplate.getId(), parameter.getId()))
							.collect(Collectors.toList());
			if (!templateAndParameters.isEmpty()) {
				bd.getBusinessDatabase().doBatchInsert(templateAndParameters);
			}
		}
		// 保存修订记录
		if (!result.getRevisionRecords().isEmpty()) {
			bd.getBusinessDatabase().doBatchInsert(result.getRevisionRecords());
		}
	}

	/**
	 * 创建模板参数关联
	 * 创建模板和参数的关联对象
	 *
	 * @param templateId 模板ID
	 * @param parameterId 参数ID
	 * @return 模板参数关联POJO
	 */
	private TemplateAndParameterPojo createTemplateAndParameter(String templateId, String parameterId) {
		TemplateAndParameterPojo tap = new TemplateAndParameterPojo();
		tap.setTemplateId(templateId);
		tap.setParameterId(parameterId);
		return tap;
	}
}
