package com.ruoyi.project.system.service.impl;

import com.ruoyi.common.constant.ProductStatic;
import com.ruoyi.common.utils.ComputeUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.project.system.domain.Product;
import com.ruoyi.project.system.domain.ProductCraft;
import com.ruoyi.project.system.domain.ProductCraftParams;
import com.ruoyi.project.system.domain.ProductMaterial;
import com.ruoyi.project.system.domain.vo.FrontPriceVo;
import com.ruoyi.project.system.domain.vo.FrontProductVo;
import com.ruoyi.project.system.domain.vo.ProductVo;
import com.ruoyi.project.system.enums.CalculateEnum;
import com.ruoyi.project.system.enums.ProductEnum;
import com.ruoyi.project.system.mapper.*;
import com.ruoyi.project.system.service.IProductService;
import com.singularsys.jep.Jep;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 商品Service业务层处理
 *
 * @author zhu
 * @date 2023-10-24
 */
@Service
public class ProductServiceImpl implements IProductService {
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductMaterialMapper productMaterialMapper;
    @Autowired
    private ProductCraftCateMapper productCraftCateMapper;
    @Autowired
    private ProductCraftMapper productCraftMapper;
    @Autowired
    private ProductCraftParamsMapper productCraftParamsMapper;

    private static final String[] ARGUMENT = {"price", "count", "number", "x"};


    /**
     * 查询商品
     *
     * @param id 商品主键
     * @return 商品
     */
    @Override
    public ProductVo selectProductById(Long id) {

        Product product = productMapper.selectProductById(id);
        if (product == null) {
            throw new IllegalArgumentException("商品不存在");
        }
        ProductVo productVo = new ProductVo();
        BeanUtils.copyProperties(product, productVo);


        return productVo;
    }

    /**
     * 查询商品列表
     *
     * @param product 商品
     * @return 商品
     */
    @Override
    public List<Product> selectProductList(Product product) {
        return productMapper.selectProductList(product);
    }

    /**
     * 新增商品
     *
     * @param product 商品
     * @return 结果
     */
    @Override
    public int insertProduct(Product product) {
        product.setCreateTime(DateUtils.getNowDate());
        return productMapper.insertProduct(product);
    }

    /**
     * 修改商品
     *
     * @param product 商品
     * @return 结果
     */
    @Override
    public int updateProduct(Product product) {
        product.setUpdateTime(DateUtils.getNowDate());
        return productMapper.updateProduct(product);
    }

    /**
     * 批量删除商品
     *
     * @param ids 需要删除的商品主键
     * @return 结果
     */
    @Override
    public int deleteProductByIds(Long[] ids) {
        return productMapper.deleteProductByIds(ids);
    }

    /**
     * 删除商品信息
     *
     * @param id 商品主键
     * @return 结果
     */
    @Override
    public int deleteProductById(Long id) {
        return productMapper.deleteProductById(id);
    }

    /**
     * 计算
     *
     * @param frontProductVo
     * @return
     */
    @Override
    public List<FrontPriceVo> compute(FrontProductVo frontProductVo) {
        Product product = productMapper.selectProductById(frontProductVo.getProductId());
        ProductMaterial productMaterial = null;
        //不一定选择工艺
        List<ProductCraft> productCraft = null;
        List<ProductCraftParams> productCraftParams = null;
        if (frontProductVo.getMaterialId() != null) {
            productMaterial = productMaterialMapper.selectProductMaterialById(frontProductVo.getMaterialId());
        }
        if (frontProductVo.getCraftId() != null) {
            productCraft = productCraftMapper.selectProductCraftByIds(frontProductVo.getCraftId());
            checkMutex(productCraft);
        }
        if (frontProductVo.getCraftParamsId() != null) {
            productCraftParams = productCraftParamsMapper.selectProductCraftParamsByIds(frontProductVo.getCraftParamsId());
        }
        List<FrontPriceVo> frontPriceVos = new ArrayList<>();

        //阶梯
        if (CalculateEnum.LADDER.equals(product.getCalculateEnum())) {
            //格式化阶梯价格
            TreeMap<String, Map<String, String>> computeMap = ComputeUtils.getCompute(product.getCompute());
            // 如果选择工艺且工艺自定义计算，则重新格式化
            if (productMaterial != null && productMaterial.getIsUseSelf() && !StringUtils.isEmpty(productMaterial.getCompute())) {
                computeMap = ComputeUtils.getCompute(productMaterial.getCompute());
            }

            //获取阶梯价格
            Map<String, String> prices = getListPrice(computeMap, product, frontProductVo.getWidth(), frontProductVo.getHeight(), frontProductVo);
            if (prices == null) {
                throw new IllegalArgumentException("未设置价格，无法获取报价");
            }
            frontPriceVos = getPrices(prices, frontProductVo.getCount());
            //第二面积价格相加
            if (frontProductVo.getWidth2() != null && frontProductVo.getHeight2() != null) {
                Map<String, String> prices2 = getListPrice(computeMap, product, frontProductVo.getWidth(), frontProductVo.getHeight(), frontProductVo);
                if (prices2 == null) {
                    throw new IllegalArgumentException("未设置价格，无法获取报价");
                }
                List<FrontPriceVo> frontPriceVos2 = getPrices(prices2, frontProductVo.getCount());
                for (int i = 0; i < frontPriceVos.size(); i++) {
                    BigDecimal totalPrice = frontPriceVos.get(i).getPrice().add(frontPriceVos2.get(i).getPrice()).setScale(0, RoundingMode.UP);
                    ;
                    frontPriceVos.get(i).setPrice(totalPrice);
                }
            }

            if (product.getIsParity() && frontPriceVos.size() >= 2 && StringUtils.isNotBlank(product.getPower())) {
                for (int i = 1; i < frontPriceVos.size(); i++) {
                    if (frontPriceVos.get(i - 1).getCount() == null) {
                        continue;
                    }
                    if (frontPriceVos.get(i).getPrice().compareTo(frontPriceVos.get(i - 1).getPrice()) < 0) {
                        frontPriceVos.get(i).setPrice(frontPriceVos.get(i).getPrice().multiply(new BigDecimal(product.getPower())).setScale(0, RoundingMode.UP));
                    }
                }
            }

            frontPriceVos.remove(0);

            if (StringUtils.isNotEmpty(frontPriceVos) && frontPriceVos.get(0).getCount() != frontProductVo.getCount()) {
                frontPriceVos.get(0).setCount(frontProductVo.getCount());
            }


        }
        //公式
        if (CalculateEnum.FORMULAR.equals(product.getCalculateEnum())) {
            FrontPriceVo frontPriceVo = new FrontPriceVo();
            frontPriceVo.setCount(frontProductVo.getCount());
            BigDecimal price = formulaToBigDecimal(product.getFormula(), frontProductVo.getWidth(), frontProductVo.getHeight(), frontProductVo.getCount(), frontProductVo.getNumber());
            if (price == null) {
                throw new IllegalArgumentException("公式有误无法算出价格");
            }
            if (frontProductVo.getWidth2() != null && frontProductVo.getHeight2() != null) {
                BigDecimal price2 = formulaToBigDecimal(product.getFormula(), frontProductVo.getWidth2(), frontProductVo.getHeight2(), frontProductVo.getCount(), frontProductVo.getNumber());
                if (price2 == null) {
                    throw new IllegalArgumentException("公式有误无法算出价格");
                }
                price.add(price2).setScale(0, RoundingMode.UP);
            }
            frontPriceVo.setPrice(price);
            frontPriceVos.add(frontPriceVo);
        }

        //计算底价
        if (StringUtils.isNotEmpty(frontPriceVos) && !product.getFormula().isEmpty() && !"price".equals(product.getFormula())) {
            Double x = getX(frontProductVo, product);
            for (FrontPriceVo frontPriceVo : frontPriceVos) {
                BigDecimal price = formulaToBigDecimal(product.getFormula(), frontPriceVo.getPrice(), frontPriceVo.getCount(), frontProductVo.getNumber(), x);
                frontPriceVo.setPrice(price);
            }
        }

        //计算工艺附加值
        for (FrontPriceVo frontPriceVo : frontPriceVos) {
            BigDecimal price = frontPriceVo.getPrice();
            if (StringUtils.isNotEmpty(productCraft)) {

                for (ProductCraft craft : productCraft) {
                    Double arg = craft.getArg() != null ? Double.valueOf(craft.getArg()) : null;
                    price = formulaToBigDecimal(craft.getCompute(), price, frontPriceVo.getCount(), frontProductVo.getNumber(), arg);

                    if (craft.getMinPrice() != null && craft.getMinPrice().compareTo(BigDecimal.ZERO) != 0) {
                        price = price.compareTo(craft.getMinPrice()) >= 0 ? price : craft.getMinPrice();
                    }
                }
            }
            if (StringUtils.isNotEmpty(productCraftParams)) {
                for (ProductCraftParams productCraftParam : productCraftParams) {
                    Double arg = productCraftParam.getArg() != null ? Double.valueOf(productCraftParam.getArg()) : null;

                    price = formulaToBigDecimal(productCraftParam.getCompute(), price, frontPriceVo.getCount(), frontProductVo.getNumber(), arg);

                    if (productCraftParam.getMinPrice() != null && productCraftParam.getMinPrice().compareTo(BigDecimal.ZERO) != 0) {
                        price = price.compareTo(productCraftParam.getMinPrice()) >= 0 ? price : productCraftParam.getMinPrice();
                    }
                }
            }
            if (!StringUtils.isEmpty(product.getStyleCompute())) {
                price = formulaToBigDecimal(product.getStyleCompute(), price, frontPriceVo.getCount(), frontProductVo.getNumber(), null);
            }
            frontPriceVo.setPrice(price);
        }
        return frontPriceVos;
    }

    @Override
    public List<Product> selectFrontProductList(Product product) {
        return productMapper.selectFrontProductList(product);
    }

    private Double getX(FrontProductVo frontProductVo, Product product) {
        if (ProductEnum.WEISHU.equals(product.getModes())) {
            //位数计算
            String[] bases = product.getBasics().split("\\*");
            double a = frontProductVo.getWidth() / Double.parseDouble(bases[0]);
            double a1 = frontProductVo.getWidth() / Double.parseDouble(bases[1]);
            double g = frontProductVo.getHeight() / Double.parseDouble(bases[0]);
            double g1 = frontProductVo.getHeight() / Double.parseDouble(bases[1]);
            return Math.min(Math.ceil(a * g), Math.ceil(a1 * g1));
        }
        if (ProductEnum.AREA.equals(product.getModes())) {
            double area = formulaToDouble(product.getBasics(), frontProductVo.getWidth(), frontProductVo.getHeight(), frontProductVo.getCount(), frontProductVo.getNumber(), null);
            return area;
        }

        return null;
    }

    /**
     * 判断是否存在互斥
     */
    private void checkMutex(List<ProductCraft> productCrafts) {
        if (productCrafts == null) {
            return;
        }
        Set<String> repels = new HashSet<>();//互斥的名称
        List<String> titles = new ArrayList<>();//选中的名称
        for (ProductCraft productCraft : productCrafts) {
            String repel = productCraft.getRepel();
            if (StringUtils.isEmpty(repel)) {
                continue;
            }
            if (StringUtils.isEmpty(repels)) {
                repels = new HashSet<>(Arrays.asList(repel.split("\\|")));
            } else {
                repels.addAll(Arrays.asList(repel.split("\\|")));
            }
            repels.add(productCraft.getTitle());
            titles.add(productCraft.getTitle());
        }
        titles.retainAll(repels);
        if (new HashSet<>(titles).size() >= 2) {//存在互斥项
            throw new IllegalArgumentException(String.join(",", titles) + "不能同时选择");
        }
    }

    /**
     * 按个数过去基本价格
     *
     * @param prices
     * @param count
     * @return
     */
    private List<FrontPriceVo> getPrices(Map<String, String> prices, Long count) {
        List<FrontPriceVo> frontPriceVos = new ArrayList<>();
        FrontPriceVo last = null;
        String lastKey = null;
        int n = 0;
        for (String integer : prices.keySet()) {
            n++;
            if (frontPriceVos.size() >= ProductStatic.MAX_GET_PRICE) {//获取多少个
                break;
            }
            if (prices.size() != n || !frontPriceVos.isEmpty()) {
                if (Long.parseLong(integer) < count && !(prices.size() == n && frontPriceVos.size() == 0)) {//数量不能少，按多的算
                    lastKey = integer;
                    continue;
                }
            }
            if (last == null) {
                last = new FrontPriceVo();
                if (lastKey != null) {
                    last.setPrice(new BigDecimal(prices.get(lastKey))).setCount(Long.valueOf(lastKey));
                }
            }
            frontPriceVos.add(new FrontPriceVo().setPrice(new BigDecimal(prices.get(integer))).setCount(Long.valueOf(integer)));
        }
        frontPriceVos.add(0, last);
        return frontPriceVos;
    }

    /**
     * 获取基本价格算法
     *
     * @param computeMap
     * @param product
     * @param frontProductVo
     * @return
     */
    private Map<String, String> getListPrice(TreeMap<String, Map<String, String>> computeMap, Product product, Double width, Double height, FrontProductVo frontProductVo) {
        if (ProductEnum.WEISHU.equals(product.getModes())) {
            //位数计算
            String[] bases = product.getBasics().split("\\*");
            double a = width / Double.parseDouble(bases[0]);
            double a1 = width / Double.parseDouble(bases[1]);
            double g = height / Double.parseDouble(bases[0]);
            double g1 = height / Double.parseDouble(bases[1]);
            Double weishu = Math.min(Math.ceil(a * g), Math.ceil(a1 * g1));
            for (String key : computeMap.keySet()) {
                //查询位数相同
                if (Double.valueOf(key).equals(weishu)) {
                    return computeMap.get(key);
                }
            }
        }
        if (ProductEnum.AREA.equals(product.getModes())) {
            double area = formulaToDouble(product.getBasics(), width, height, frontProductVo.getCount(), frontProductVo.getNumber(), null);
            for (String key : computeMap.keySet()) {
                //判断面积大小，面积只能大不能小
                if (Double.parseDouble(key) < area) {
                    continue;
                }
                return computeMap.get(key);
            }
        }

        if (ProductEnum.LONGWIDTH.equals(product.getModes())) {

            for (String key : computeMap.keySet()) {
                String[] keys = key.split(",");//切割多个长宽
                boolean result = false;
                for (String s : keys) {
                    String[] wh = s.split("\\*");//切割出长宽
                    if ((Double.parseDouble(wh[0]) > width && Double.parseDouble(wh[1]) > height) || (Double.parseDouble(wh[1]) > width && Double.parseDouble(wh[0]) > height)) {
                        result = true;
                        break;
                    }
                }
                if (!result) {
                    continue;
                }
                return computeMap.get(key);
            }
        }
        return null;
    }

    private Double formulaToDouble(String formula, double width, double height, Long count, Long number, Long x) {
        if (StringUtils.isEmpty(formula)) {
            return width * height;
        }
        String regex = "(?!width|height|count|number|x|\\+|-|\\*|/|\\d)\\b\\w+\\b";

        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(regex);

        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(formula);

        // 判断是否存在除了 "price"、"count" 和 "number" 之外的其他字符
        if (matcher.find()) {
            System.out.println("方法存在未知数 : " + matcher.group(0));
            return width * height;
        }
        try {

            Jep jep = new Jep();
            jep.addVariable("width", width);//基本价格
            jep.addVariable("height", height);//基本价格
            jep.addVariable("count", count);//数量
            jep.addVariable("number", number);//款数
            if (x != null) {
                jep.addVariable("x", x);//参数值
            }
            jep.parse(formula);
            return new Double(jep.evaluate().toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return width * height;
    }

    private BigDecimal formulaToBigDecimal(String formula, double width, double height, Long count, Long number) {
        if (StringUtils.isEmpty(formula)) {
            return null;
        }
        String regex = "(?!width|count|number|height|\\+|-|\\*|/|\\d)\\b\\w+\\b";

        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(regex);

        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(formula);

        // 判断是否存在除了 "price"、"count" 和 "number" 之外的其他字符
        if (matcher.find()) {
            System.out.println("方法存在未知数 : " + matcher.group(0));
            return null;
        }
        try {

            Jep jep = new Jep();
            jep.addVariable("width", width);//基本价格
            jep.addVariable("count", count);//数量
            jep.addVariable("number", number);//款数
            jep.addVariable("height", height);//参数值
            jep.parse(formula);
            return new BigDecimal(jep.evaluate().toString()).setScale(0, RoundingMode.UP);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return new BigDecimal(0);
    }

    private BigDecimal formulaToBigDecimal(String formula, BigDecimal price, Long count, Long number, Double x) {
        if (StringUtils.isEmpty(formula)) {
            return price;
        }
        String regex = "(?!price|count|number|x|\\+|-|\\*|/|\\d)\\b\\w+\\b";

        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(regex);

        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(formula);

        // 判断是否存在除了 "price"、"count" 和 "number" 之外的其他字符
        if (matcher.find()) {
            System.out.println("方法存在未知数 : " + matcher.group(0));
            return price;
        }
        try {

            Jep jep = new Jep();
            jep.addVariable("price", price);//基本价格
            jep.addVariable("count", count);//数量
            jep.addVariable("number", number);//款数
            if (x != null) {
                jep.addVariable("x", x);//参数值
            }
            jep.parse(formula);
            return new BigDecimal(jep.evaluate().toString()).setScale(0, BigDecimal.ROUND_UP);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new BigDecimal(0);
    }
}
