package com.fjhx.uitl.code;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fjhx.service.apply.ApplyPurchaseService;
import com.fjhx.service.check.CheckInfoService;
import com.fjhx.service.customer.CustomerInfoService;
import com.fjhx.service.form.FormOverflowLossService;
import com.fjhx.service.order.OrderInfoService;
import com.fjhx.service.product.ProductInfoService;
import com.fjhx.service.product.ProductSpuService;
import com.fjhx.service.purchase.PurchaseService;
import com.fjhx.service.quality.QualityInfoService;
import com.fjhx.service.stock.StockJournalService;
import com.fjhx.service.supplier.SupplierService;
import com.fjhx.utils.Assert;
import lombok.Getter;

import java.util.Date;
import java.util.Map;

@Getter
public enum CodeEnum {

    // 供应商
    SUPPLIER("GY", null, "code", 5, SupplierService.class),
    // spu
    SPU("SPU", null, "code", 5, ProductSpuService.class),
    //申购单
    APPLY_PURCHASE("AP", "yyyyMM-", "code", 5, ApplyPurchaseService.class),
    // 物料
    MATERIAL("M", null, "code", 5, ProductInfoService.class),
    // 产品_成品
    PRODUCT_FINISHED("PF", null, "code", 5, ProductInfoService.class),
    // 产品_半成品
    PRODUCT_PARTIALLY_PREPARED("PP", null, "code", 5, ProductInfoService.class),
    //采购
    PURCHASE("PO", "yyyyMM-", "code", 5, PurchaseService.class),
    //客户
    CUSTOMER("C", null, "code", 5, CustomerInfoService.class),
    //销售订单
    ORDER_SALES("SO", null, "code", 5, OrderInfoService.class),
    // 京东订单
    ORDER_JD("JD", null, "code", 5, OrderInfoService.class),
    // 手动出库流水单号
    OUT_JOURNAL("O", "yyyyMM-", "code", 5, StockJournalService.class),
    // 京东出库流水单号
    JD_OUT_JOURNAL("JDO", "yyyyMM-", "code", 5, StockJournalService.class),
    // 销售出库流水单号
    S_OUT_JOURNAL("SO", "yyyyMM-", "code", 5, StockJournalService.class),
    // 手动入库流水单号
    IN_JOURNAL("I", "yyyyMM-", "code", 5, StockJournalService.class),
    // 京东入库流水单号,
    JD_IN_JOURNAL("JDI", "yyyyMM-", "code", 5, StockJournalService.class),
    // 销售入库流水单号
    S_IN_JOURNAL("SI", "yyyyMM-", "code", 5, StockJournalService.class),
    // 采购入库流水单号
    IN_PURCHASE("POI", "yyyyMM-", "code", 5, StockJournalService.class),
    // 盘点单号
    CHECK_CODE("CK", "yyyyMM-", "code", 5, CheckInfoService.class),
    // 报溢单号
    FORM_OVERFLOW("LR", "yyyyMM-", "code", 5, FormOverflowLossService.class),
    // 报损单号
    FORM_LOSS("FL", "yyyyMM-", "code", 5, FormOverflowLossService.class),
    // 质检单号
    QUALITY("QA", "yyyyMM-", "code", 5, QualityInfoService.class),

    ;

    CodeEnum(String prefix, String dateFormat, String codeFieldName, Integer length, Class<? extends IService<?>> serviceCls) {
        this.prefix = prefix;
        this.dateFormat = dateFormat;
        this.length = length;
        this.codeFieldName = codeFieldName;
        this.service = SpringUtil.getBean(serviceCls);
    }

    // 编码前缀
    private final String prefix;
    // 编码加日期规则
    private final String dateFormat;
    // 长度
    private final Integer length;
    // 编码字段名
    private final String codeFieldName;
    // service
    private final IService<?> service;

    /**
     * 获取键值对
     */
    public String getCode() {
        String itemPrefix;

        if (ObjectUtil.isNotEmpty(dateFormat)) {
            Date date = new Date();
            String format = DateUtil.format(date, dateFormat);
            itemPrefix = prefix + format;
        } else {
            itemPrefix = prefix;
        }

        Object obj = service.query()
                .likeRight(codeFieldName, itemPrefix)
                .orderByDesc(codeFieldName)
                .last("limit 1")
                .one();

        if (obj == null) {
            return itemPrefix + autoGenericCode(length, 0);
        }

        Map<String, Object> map = Convert.toMap(String.class, Object.class, obj);

        String code = Convert.toStr(map.get(codeFieldName));
        Integer codeNum = Convert.toInt(code.substring(itemPrefix.length()));
        Assert.notEmpty(codeNum, "自定义编码与系统编码生成规则冲突，暂时无法生成编码，请联系管理员");

        return itemPrefix + autoGenericCode(length, codeNum);
    }

    /**
     * 获取键值对
     */
    public String getCode(String code) {
        if (ObjectUtil.isNotEmpty(code)) {
            Long count = service.query().eq(codeFieldName, code).count();
            Assert.eqZero(count, "编码已存在");
            return code;
        } else {
            return getCode();
        }
    }

    /**
     * 不够位数的在前面补0，保留num的长度位数字
     */
    private static String autoGenericCode(int length, Integer codeNum) {
        return String.format("%0" + length + "d", codeNum + 1);
    }

}
