package com.ruoyi.system.utils;

import com.ruoyi.common.constant.AllEnum;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.doc.RqKTV1Standard;
import com.ruoyi.system.domain.doc.other.RqOrderItem;
import com.ruoyi.system.domain.doc.other.RqTableTemplateMerchV1;
import com.ruoyi.system.domain.doc.other.RqTableTemplateStandardChaReqItem;
import com.ruoyi.system.domain.doc.other.RqTableTemplateStandardV1HeatTreatHead;
import com.ruoyi.system.domain.dto.excel.ProcessOrderData;
import com.ruoyi.system.mapper.doc.DocRqKTV1StandardRepository;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * ???????????????????????? / ????? / ????????????a??
 */
public final class ProcessOrderKnowledgeUtils {

    private static final int CHEMICAL_ROW_1 = 11;
    private static final int CHEMICAL_ROW_2 = 13;
    private static final int HEAT_TREATMENT_ROW = 15;

    private static final Map<String, int[]> CHEMICAL_CELL_MAP = buildChemicalCellMap();

    private ProcessOrderKnowledgeUtils() {
    }

    public static ProcessOrderData enrichFromCustomerStandard(RqOrderItem orderItem,
            DocRqKTV1StandardRepository repository) {
        ProcessOrderData extras = new ProcessOrderData();
        RqKTV1Standard standard = resolveCustomerStandard(orderItem, repository);
        if (standard == null) {
            return extras;
        }
        extras.setChaReqAsPer(StringUtils.defaultString(standard.getChaReqAsPer()));
        extras.setChemicalLimits(buildChemicalLimits(standard.getChaReqItemsJson()));
        extras.setHeatTreatmentText(buildHeatTreatmentText(standard));
        extras.setMechanicalText(buildMechanicalText(standard.getMerchJson()));
        return extras;
    }

    public static void applyKnowledgeToSheet(Sheet sheet, ProcessOrderData orderData) {
        if (sheet == null || orderData == null) {
            return;
        }
        fillChemicalLimits(sheet, orderData.getChemicalLimits());
        fillMergedRowText(sheet, HEAT_TREATMENT_ROW, 0, buildProcessRequirementText(orderData));
    }

    private static String buildProcessRequirementText(ProcessOrderData orderData) {
        List<String> parts = new ArrayList<>();
        if (StringUtils.isNotBlank(orderData.getHeatTreatmentText())) {
            parts.add("?????????\n" + orderData.getHeatTreatmentText().trim());
        }
        if (StringUtils.isNotBlank(orderData.getMechanicalText())) {
            parts.add("????§Ö?????\n" + orderData.getMechanicalText().trim());
        }
        return String.join("\n\n", parts);
    }

    private static RqKTV1Standard resolveCustomerStandard(RqOrderItem orderItem,
            DocRqKTV1StandardRepository repository) {
        if (orderItem == null) {
            return null;
        }
        RqKTV1Standard customerStandard = orderItem.getCustomerStandard();
        if ((customerStandard == null || CollectionUtils.isEmpty(customerStandard.getChaReqItemsJson()))
                && StringUtils.isNotBlank(orderItem.getCustomerStandardID())
                && repository != null) {
            customerStandard = repository.findById(orderItem.getCustomerStandardID()).orElse(null);
        }
        if (customerStandard == null && StringUtils.isNotBlank(orderItem.getMaterial()) && repository != null) {
            List<RqKTV1Standard> standards = repository.findByBlankMaterialType(orderItem.getMaterial());
            customerStandard = standards.stream()
                    .filter(s -> AllEnum.NUMBER.ZERO.getCode().equals(s.getParentId()))
                    .findFirst()
                    .orElse(null);
        }
        return customerStandard;
    }

    private static Map<String, String> buildChemicalLimits(List<RqTableTemplateStandardChaReqItem> items) {
        Map<String, String> limits = new HashMap<>();
        if (CollectionUtils.isEmpty(items)) {
            return limits;
        }
        for (RqTableTemplateStandardChaReqItem item : items) {
            if (item == null || StringUtils.isBlank(item.getEle())) {
                continue;
            }
            if (StringUtils.isBlank(item.getMin()) && StringUtils.isBlank(item.getMax())) {
                continue;
            }
            String key = normalizeElementKey(item.getEle());
            if (StringUtils.isNotBlank(key)) {
                limits.put(key.toUpperCase(), formatChaLimit(item.getMin(), item.getMax()));
            }
        }
        return limits;
    }

    private static String buildHeatTreatmentText(RqKTV1Standard standard) {
        if (standard == null) {
            return "";
        }
        List<String> parts = new ArrayList<>();
        if (StringUtils.isNotBlank(standard.getHeatTreatAsPer())) {
            parts.add("As Per: " + standard.getHeatTreatAsPer().trim());
        }
        if (StringUtils.isNotBlank(standard.getHeatTreatReportNo())) {
            parts.add("Report No: " + standard.getHeatTreatReportNo().trim());
        }
        String processText = formatHeatTreatmentProcess(standard);
        if (StringUtils.isNotBlank(processText)) {
            parts.add(processText);
        }
        return String.join("\n", parts);
    }

    private static String formatHeatTreatmentProcess(RqKTV1Standard standard) {
        if (standard.getHeatTreatJson() == null || standard.getHeatTreatJson().isEmpty()) {
            return "";
        }
        List<String> parts = new ArrayList<>();
        for (RqTableTemplateStandardV1HeatTreatHead head : standard.getHeatTreatJson()) {
            if (head == null) {
                continue;
            }
            String processCode = StringUtils.defaultIfBlank(head.getProcess(), "");
            String processLabel = processCode;
            if (StringUtils.isNotBlank(processCode)) {
                String dictLabel = DictUtils.getDictLabel("heat_process", processCode);
                if (StringUtils.isNotBlank(dictLabel)) {
                    processLabel = dictLabel;
                }
            }
            String remark = StringUtils.defaultIfBlank(head.getRemark(), "").trim();
            String line = StringUtils.isNotBlank(remark) ? processLabel + " " + remark : processLabel;
            if (StringUtils.isNotBlank(line.trim())) {
                parts.add(line.trim());
            }
        }
        return String.join("??", parts);
    }

    private static String buildMechanicalText(RqTableTemplateMerchV1 merchJson) {
        if (merchJson == null) {
            return "";
        }
        List<String> parts = new ArrayList<>();
        if (StringUtils.isNotBlank(merchJson.getAsPer())) {
            parts.add("As Per: " + merchJson.getAsPer().trim());
        }
        if (StringUtils.isNotBlank(merchJson.getSpecAsPer())) {
            parts.add("Spec: " + merchJson.getSpecAsPer().trim());
        }
        if (StringUtils.isNotBlank(merchJson.getReportNo())) {
            parts.add("Report No: " + merchJson.getReportNo().trim());
        }
        appendRange(parts, "Yield Strength", merchJson.getYieldStrengthMin(), merchJson.getYieldStrengthMax(), " MPa");
        appendRange(parts, "Tensile Strength", merchJson.getTensileMin(), merchJson.getTensileMax(), " MPa");
        appendRange(parts, "Elongation", merchJson.getElongationMin(), merchJson.getElongationMax(), " %");
        appendRange(parts, "Reduction of Area", merchJson.getReductionMin(), merchJson.getReductionMax(), " %");
        if (StringUtils.isNotBlank(merchJson.getSpecHardness())) {
            parts.add("Hardness: " + merchJson.getSpecHardness().trim());
        }
        appendRange(parts, "Hardness 1", merchJson.getHardness1Min(), merchJson.getHardness1Max(), "");
        appendRange(parts, "Hardness Avg", merchJson.getHardnessAvgMin(), merchJson.getHardnessAvgMax(), "");
        return parts.stream().filter(StringUtils::isNotBlank).collect(Collectors.joining("??"));
    }

    private static void appendRange(List<String> parts, String label, String min, String max, String unit) {
        String range = formatRange(min, max, unit);
        if (StringUtils.isNotBlank(range)) {
            parts.add(label + ": " + range);
        }
    }

    private static String formatRange(String min, String max, String unit) {
        if (StringUtils.isNotBlank(min) && StringUtils.isNotBlank(max)) {
            return min.trim() + "-" + max.trim() + unit;
        }
        if (StringUtils.isNotBlank(min)) {
            return "??" + min.trim() + unit;
        }
        if (StringUtils.isNotBlank(max)) {
            return "??" + max.trim() + unit;
        }
        return "";
    }

    private static String formatChaLimit(String min, String max) {
        if (StringUtils.isNotBlank(min) && StringUtils.isNotBlank(max)) {
            if (min.trim().equals(max.trim())) {
                return min.trim();
            }
            return min.trim() + "-" + max.trim();
        }
        if (StringUtils.isNotBlank(max)) {
            String trimmed = max.trim();
            if (trimmed.startsWith("??") || trimmed.startsWith("??") || trimmed.startsWith("<") || trimmed.startsWith(">")) {
                return trimmed;
            }
            return "??" + trimmed;
        }
        if (StringUtils.isNotBlank(min)) {
            String trimmed = min.trim();
            if (trimmed.startsWith("??") || trimmed.startsWith("??") || trimmed.startsWith("<") || trimmed.startsWith(">")) {
                return trimmed;
            }
            return "??" + trimmed;
        }
        return "";
    }

    private static void fillChemicalLimits(Sheet sheet, Map<String, String> chemicalLimits) {
        if (chemicalLimits == null || chemicalLimits.isEmpty()) {
            return;
        }
        for (Map.Entry<String, String> entry : chemicalLimits.entrySet()) {
            int[] pos = CHEMICAL_CELL_MAP.get(entry.getKey().toUpperCase());
            if (pos == null || StringUtils.isBlank(entry.getValue())) {
                continue;
            }
            setCellValue(sheet, pos[0], pos[1], entry.getValue());
        }
    }

    private static void fillMergedRowText(Sheet sheet, int rowIndex, int colIndex, String text) {
        if (StringUtils.isBlank(text)) {
            return;
        }
        setCellValue(sheet, rowIndex, colIndex, text.trim());
    }

    private static void setCellValue(Sheet sheet, int rowIndex, int colIndex, String value) {
        Row row = sheet.getRow(rowIndex);
        if (row == null) {
            row = sheet.createRow(rowIndex);
        }
        Cell cell = row.getCell(colIndex);
        if (cell == null) {
            cell = row.createCell(colIndex);
        }
        cell.setCellValue(value);
    }

    private static String normalizeElementKey(String ele) {
        if (StringUtils.isBlank(ele)) {
            return "";
        }
        String normalized = ele.trim().toUpperCase();
        normalized = normalized.replace("%", "").replace(".", "").replace("??", "");
        if (normalized.contains("?????") || normalized.equals("CE") || normalized.equals("CEQ")) {
            return "CE";
        }
        if (normalized.contains("PREN")) {
            return "PREN";
        }
        if (normalized.equals("C")) {
            return "C";
        }
        StringBuilder symbol = new StringBuilder();
        for (char ch : normalized.toCharArray()) {
            if ((ch >= 'A' && ch <= 'Z') || (symbol.length() > 0 && ch >= 'A' && ch <= 'Z')) {
                symbol.append(ch);
            } else if (symbol.length() > 0) {
                break;
            }
        }
        return symbol.toString();
    }

    private static Map<String, int[]> buildChemicalCellMap() {
        Map<String, int[]> map = new LinkedHashMap<>();
        map.put("C", new int[]{CHEMICAL_ROW_1, 0});
        map.put("MN", new int[]{CHEMICAL_ROW_1, 2});
        map.put("SI", new int[]{CHEMICAL_ROW_1, 6});
        map.put("P", new int[]{CHEMICAL_ROW_1, 11});
        map.put("S", new int[]{CHEMICAL_ROW_1, 12});
        map.put("CR", new int[]{CHEMICAL_ROW_1, 17});
        map.put("NI", new int[]{CHEMICAL_ROW_1, 18});
        map.put("MO", new int[]{CHEMICAL_ROW_1, 21});
        map.put("CU", new int[]{CHEMICAL_ROW_1, 25});
        map.put("V", new int[]{CHEMICAL_ROW_1, 28});
        map.put("NB", new int[]{CHEMICAL_ROW_1, 31});
        map.put("N", new int[]{CHEMICAL_ROW_1, 35});
        map.put("AL", new int[]{CHEMICAL_ROW_2, 0});
        map.put("CO", new int[]{CHEMICAL_ROW_2, 2});
        map.put("TI", new int[]{CHEMICAL_ROW_2, 6});
        map.put("FE", new int[]{CHEMICAL_ROW_2, 11});
        map.put("W", new int[]{CHEMICAL_ROW_2, 12});
        map.put("CE", new int[]{CHEMICAL_ROW_2, 17});
        map.put("PREN", new int[]{CHEMICAL_ROW_2, 18});
        return map;
    }
}
