package com.hxhq.business.utils;

import com.hxhq.common.core.exception.ServiceException;
import com.hxhq.common.core.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 单位换算工具
 *
 * @author HanLong
 */
public class UnitTools {

    private static String[] unitList = {"pL", "nL", "uL", "mL", "L", "pg", "ng", "ug", "mg", "g", "kg"};

    /**
     * 体积单位
     */
    public static String[] VOLUME_UNIT_LIST = {"pL", "nL", "uL", "mL", "L"};
    /**
     * 质量单位
     */
    public static String[] WEIGHT_UNIT_LIST = {"pg", "ng", "ug", "mg", "g", "kg"};

    /**
     * 单位与皮升(pL)、皮克(pg)的换算关系（1单位 = 多少 pL）
     */
    private static final Map<String, BigDecimal> UNIT_TO_LITER = new HashMap<>();

    static {
        UNIT_TO_LITER.put("pL", new BigDecimal(1.0));                 // 皮升（基准）
        UNIT_TO_LITER.put("nL", new BigDecimal(1_000.0));              // 纳升 = 1000 pL
        UNIT_TO_LITER.put("uL", new BigDecimal(1_000_000.0));           // 微升 = 1,000,000 pL
        UNIT_TO_LITER.put("mL", new BigDecimal(1_000_000_000.0));       // 毫升 = 1,000,000,000 pL
        UNIT_TO_LITER.put("L", new BigDecimal(1_000_000_000_000.0));    // 升 = 1,000,000,000,000 pL

        UNIT_TO_LITER.put("pg", new BigDecimal(1.0));                 // 皮克
        UNIT_TO_LITER.put("ng", new BigDecimal(1_000.0));              // 纳克 = 1000 pg
        UNIT_TO_LITER.put("ug", new BigDecimal(1_000_000.0));           // 微克 = 1,000,000 pg
        UNIT_TO_LITER.put("mg", new BigDecimal(1_000_000_000.0));       // 毫克 = 1,000,000,000 pg
        UNIT_TO_LITER.put("g", new BigDecimal(1_000_000_000_000.0));    // 克 = 1,000,000,000,000 pg
        UNIT_TO_LITER.put("kg", new BigDecimal(1_000_000_000_000_000.0));    // 千克 = 1,000,000,000,000,000 pg
    }

    /**
     * 体积相加
     *
     * @param kc      当前库存
     * @param kcdw    当前库存单位
     * @param addKc   增加库存
     * @param addKcdw 增加库存单位
     * @return
     */
    public static String addTj(String kc, String kcdw, String addKc, String addKcdw) {
        validateUnit(kcdw);
        validateUnit(addKcdw);
        BigDecimal kcValue = formatKc(kc);
        BigDecimal addKcValue = formatKc(addKc);
        addKcValue = convert(addKcValue, addKcdw, kcdw);
        kcValue = kcValue.add(addKcValue);

        return kcValue.toString();
    }

    /**
     * 体积相减
     *
     * @param kc      当前库存
     * @param kcdw    当前库存单位
     * @param subKc   扣减库存
     * @param subKcdw 扣减库存单位
     * @return
     */
    public static String subTj(String kc, String kcdw, String subKc, String subKcdw) {
        validateUnit(kcdw);
        validateUnit(subKcdw);
        BigDecimal kcValue = formatKc(kc);
        BigDecimal subKcValue = formatKc(subKc);
        subKcValue = convert(subKcValue, subKcdw, kcdw);
        kcValue = kcValue.subtract(subKcValue);

        DecimalFormat df = new DecimalFormat("#");

        return df.format(kcValue);
    }

    private static BigDecimal formatKc(String kc) {
        if (StringUtils.isEmpty(kc)) {
            return BigDecimal.ZERO;
        }
        if (!NumberUtils.isParsable(kc)) {
            throw new ServiceException("不支持的库存数量" + kc);
        }
        return new BigDecimal(kc);
    }

    /**
     * 体积单位换算
     *
     * @param value    需要转换的数值
     * @param fromUnit 原始单位
     * @param toUnit   目标单位
     * @return 转换后的数值
     * @throws IllegalArgumentException 当单位不支持时抛出异常
     */
    public static BigDecimal convert(BigDecimal value, String fromUnit, String toUnit) {
        // 验证单位是否支持
        if (!UNIT_TO_LITER.containsKey(fromUnit)) {
            throw new ServiceException("不支持的单位：" + fromUnit);
        }
        if (!UNIT_TO_LITER.containsKey(toUnit)) {
            throw new ServiceException("不支持的单位：" + toUnit);
        }

        // 如果单位相同，直接返回
        if (fromUnit.equals(toUnit)) {
            return value;
        }

        // 转换为基准单位
        BigDecimal valueInLiters = value.multiply(UNIT_TO_LITER.get(fromUnit));
        BigDecimal to = UNIT_TO_LITER.get(toUnit);
        // 从基准单位转换为目标单位
        return valueInLiters.divide(to);
    }

    /**
     * 转换为基础单位
     *
     * @param value    数值
     * @param fromUnit 原单位
     * @return
     */
    public static BigDecimal convert2Basic(String value, String fromUnit) {
        try {
            if (StringUtils.isEmpty(value) || !NumberUtils.isParsable(value)) {
                return BigDecimal.ZERO;
            }
            // 验证单位是否支持
            if (!UNIT_TO_LITER.containsKey(fromUnit)) {
                return new BigDecimal(value);
            }

            String toUnit = "";
            if (Arrays.asList(VOLUME_UNIT_LIST).contains(fromUnit)) {
                toUnit = "pL";
            } else if (Arrays.asList(WEIGHT_UNIT_LIST).contains(fromUnit)) {
                toUnit = "pg";
            }

            // 如果单位相同，直接返回
            if (fromUnit.equals(toUnit)) {
                return new BigDecimal(value);
            }

            // 转换为基准单位
            BigDecimal valueInLiters = new BigDecimal(value).multiply(UNIT_TO_LITER.get(fromUnit));
            BigDecimal to = UNIT_TO_LITER.get(toUnit);
            // 从基准单位转换为目标单位
            return valueInLiters.divide(to);
        } catch (Exception ex) {
            return BigDecimal.ZERO;
        }
    }

    /**
     * 从基础单位转换为指定单位
     *
     * @param value  数值
     * @param toUnit 原单位
     * @return
     */
    public static BigDecimal convert(BigDecimal value, String toUnit) {
        if (value == null) {
            return BigDecimal.ZERO;
        }
        // 验证单位是否支持
        if (!UNIT_TO_LITER.containsKey(toUnit)) {
            return value;
        }

        String fromUnit = "";
        if (Arrays.asList(VOLUME_UNIT_LIST).contains(toUnit)) {
            fromUnit = "pL";
        } else if (Arrays.asList(WEIGHT_UNIT_LIST).contains(toUnit)) {
            fromUnit = "pg";
        }

        return convert(value, fromUnit, toUnit);
    }

    private static void validateUnit(String unit) {
        boolean isValid = false;
        for (String validUnit : unitList) {
            if (validUnit.equalsIgnoreCase(unit)) {
                isValid = true;
                break;
            }
        }
        if (!isValid) {
            throw new ServiceException("不支持的单位: " + unit);
        }
    }

    public static void main(String[] args) {
       /* System.out.println("1 L = " + convert(new BigDecimal(1), "L", "mL") + " mL");           // 1000.0
        System.out.println("1 mL = " + convert(new BigDecimal(1), "mL", "uL") + " uL");         // 1000.0
        System.out.println("1 uL = " + convert(new BigDecimal(1), "uL", "nL") + " nL");         // 1000.0
        System.out.println("1 nL = " + convert(new BigDecimal(1), "nL", "pL") + " pL");         // 1000.0
        System.out.println("1 pL = " + convert(new BigDecimal(1), "pL", "L") + " L");           // 1.0E-12
        System.out.println("1000 mL = " + convert(new BigDecimal(1000), "mL", "L") + " L");     // 1.0
        System.out.println("1.5 L = " + convert(new BigDecimal(1.5), "L", "uL") + " uL");       // 1500,000.0
*/

        System.out.println("1 kg = " + convert(new BigDecimal(1), "kg", "g") + " g");           // 1000.0
        System.out.println("1 mg = " + convert(new BigDecimal(1), "mg", "g") + " g");         // 1000.0
        System.out.println("1 ug = " + convert(new BigDecimal(1), "ug", "g") + " g");         // 1000.0
        System.out.println("1 ng = " + convert(new BigDecimal(1), "ng", "g") + " g");         // 1000.0
        System.out.println("1 pg = " + convert(new BigDecimal(1), "pg", "g") + " g");           // 1.0E-12
        System.out.println("1000 mg = " + convert(new BigDecimal(1000), "mg", "g") + " g");     // 1.0
        System.out.println("1.5 kg = " + convert(new BigDecimal(1.5), "kg", "g") + " g");       // 1500.0
    }
}
