package com.talentcard.server.business.portal; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; import java.util.Locale; import java.util.Map; import tools.jackson.core.type.TypeReference; import tools.jackson.databind.ObjectMapper; public final class ProductPriceCalculator { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final TypeReference>> RIGHTS_TYPE = new TypeReference<>() {}; private ProductPriceCalculator() { } static ProductPrice calculate(Object originalPrice, Object salePrice, Object rightsConfig, Object cardLevel) { return calculate(originalPrice, salePrice, rightsConfig, cardLevel, 0); } static ProductPrice calculate(Object originalPrice, Object salePrice, Object rightsConfig, Object cardLevel, int usedFreeCount) { BigDecimal fallbackSale = money(salePrice); BigDecimal original = money(originalPrice); if (original.signum() <= 0) { original = fallbackSale; } BigDecimal calculatedSale = fallbackSale.signum() > 0 ? fallbackSale : original; Map right = matchingRight(rightsConfig, cardLevel); if (right != null && original.signum() > 0) { boolean free = booleanValue(right.get("free")); int limitCount = intValue(right.get("limitCount")); boolean freeAvailable = free && (limitCount <= 0 || usedFreeCount < limitCount); if (freeAvailable) { calculatedSale = BigDecimal.ZERO; } else { BigDecimal discount = discountValue(right.get(free ? "exceedDiscount" : "discount")); if (discount.signum() > 0) { calculatedSale = original.multiply(discount) .divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP); } } } return new ProductPrice(original, calculatedSale.setScale(2, RoundingMode.HALF_UP), right != null); } public static ProductRight productRight(Object rightsConfig, Object cardLevel) { Map right = matchingRight(rightsConfig, cardLevel); if (right == null) return null; boolean free = booleanValue(right.get("free")); return new ProductRight( free, intValue(right.get("limitCount")), text(right.get("resetCycle")), discountValue(right.get(free ? "exceedDiscount" : "discount"))); } private static Map matchingRight(Object rightsConfig, Object cardLevel) { String normalizedCardLevel = normalizeCardLevel(cardLevel); if (normalizedCardLevel.isBlank() || rightsConfig == null) return null; for (Map right : parseRights(rightsConfig)) { if (!booleanValue(right.get("enabled"))) continue; if (normalizedCardLevel.equals(normalizeCardLevel(right.get("level")))) return right; } return null; } private static List> parseRights(Object value) { if (value instanceof List list) { return list.stream() .filter(Map.class::isInstance) .map(item -> (Map) item) .toList(); } String text = String.valueOf(value).trim(); if (text.isBlank()) return List.of(); try { return OBJECT_MAPPER.readValue(text, RIGHTS_TYPE); } catch (Exception ignored) { return List.of(); } } private static String normalizeCardLevel(Object value) { if (value == null) return ""; String raw = String.valueOf(value).trim(); String upper = raw.toUpperCase(Locale.ROOT); if (upper.contains("EXCELLENT") || raw.contains("卓越")) return "EXCELLENT"; if (upper.contains("OUTSTANDING") || raw.contains("杰出")) return "OUTSTANDING"; if (upper.contains("ELITE") || raw.contains("菁英") || raw.contains("精英")) return "ELITE"; return upper; } private static boolean booleanValue(Object value) { if (value instanceof Boolean bool) return bool; if (value instanceof Number number) return number.intValue() != 0; String text = value == null ? "" : String.valueOf(value).trim(); return "true".equalsIgnoreCase(text) || "1".equals(text) || "yes".equalsIgnoreCase(text); } private static int intValue(Object value) { if (value instanceof Number number) return number.intValue(); try { String text = value == null ? "" : String.valueOf(value).trim(); if (text.isBlank()) return 0; return new BigDecimal(text).intValue(); } catch (Exception ignored) { return 0; } } private static String text(Object value) { return value == null ? "" : String.valueOf(value).trim(); } private static BigDecimal discountValue(Object value) { BigDecimal discount = money(value); if (discount.compareTo(BigDecimal.ZERO) <= 0 || discount.compareTo(BigDecimal.TEN) > 0) { return BigDecimal.ZERO; } return discount; } private static BigDecimal money(Object value) { if (value == null) return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); try { if (value instanceof BigDecimal decimal) return decimal.setScale(2, RoundingMode.HALF_UP); return new BigDecimal(String.valueOf(value).trim()).setScale(2, RoundingMode.HALF_UP); } catch (Exception ignored) { return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); } } record ProductPrice(BigDecimal originalPrice, BigDecimal salePrice, boolean personalized) { } public record ProductRight(boolean free, int limitCount, String resetCycle, BigDecimal discount) { } }