package com.fjhx.common.service.coding.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.area.entity.po.CustomizeArea;
import com.fjhx.area.service.CustomizeAreaService;
import com.fjhx.common.entity.coding.bo.CustomerCodeAndCountryId;
import com.fjhx.common.entity.coding.dto.CodingRuleDto;
import com.fjhx.common.entity.coding.dto.CodingRuleSelectDto;
import com.fjhx.common.entity.coding.dto.RuleVo;
import com.fjhx.common.entity.coding.po.CodingRule;
import com.fjhx.common.entity.coding.po.CodingRuleAuto;
import com.fjhx.common.entity.coding.vo.CodingRulePageVo;
import com.fjhx.common.enums.CodingRuleEnum;
import com.fjhx.common.enums.RuleTypeEnum;
import com.fjhx.common.mapper.coding.CodingRuleMapper;
import com.fjhx.common.service.coding.CodingRuleAutoService;
import com.fjhx.common.service.coding.CodingRuleCustomerService;
import com.fjhx.common.service.coding.CodingRuleService;
import com.obs.services.internal.ServiceException;
import com.ruoyi.common.core.domain.BaseIdPo;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * <p>
 * 编码规则 服务实现类
 * </p>
 *
 * @author
 * @since 2023-04-13
 */
@Service
public class CodingRuleServiceImpl extends ServiceImpl<CodingRuleMapper, CodingRule> implements CodingRuleService {

    @Autowired
    private CodingRuleCustomerService codingRuleCustomerService;

    @Autowired
    private CustomizeAreaService customizeAreaService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private CodingRuleAutoService codingRuleAutoService;

    @Override
    public Page<CodingRulePageVo> getPage(CodingRuleSelectDto dto) {

        Integer pageNum = dto.getPageNum();
        Integer pageSize = dto.getPageSize();

        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = pageNum * pageSize;

        int tempIndex = 0;

        List<CodingRulePageVo> codingRulePageVoList = new ArrayList<>();
        List<String> keyList = new ArrayList<>();

        for (CodingRuleEnum codingRuleEnum : CodingRuleEnum.values()) {
            if (StrUtil.isNotBlank(dto.getKeyword())) {

                if (codingRuleEnum.getName().contains(dto.getKeyword())) {
                    tempIndex = getTempIndex(startIndex, endIndex, tempIndex, codingRulePageVoList, keyList, codingRuleEnum);
                }

            } else {
                tempIndex = getTempIndex(startIndex, endIndex, tempIndex, codingRulePageVoList, keyList, codingRuleEnum);
            }

        }

        Page<CodingRulePageVo> page = dto.getPage();
        page.setRecords(codingRulePageVoList);
        page.setTotal(tempIndex);

        if (keyList.size() == 0) {
            return page;
        }

        Map<String, CodingRule> kEntity = mapKEntity(CodingRule::getCodingKey, q -> q.in(CodingRule::getCodingKey, keyList));

        for (CodingRulePageVo codingRulePageVo : codingRulePageVoList) {
            CodingRule codingRule = kEntity.get(codingRulePageVo.getCodingKey());
            if (codingRule == null) {
                continue;
            }
            codingRulePageVo.setId(codingRule.getId());
            codingRulePageVo.setCodingDemo(codingRule.getCodingDemo());
            codingRulePageVo.setRuleVoList(JSON.parseArray(codingRule.getRuleJson(), RuleVo.class));
            codingRulePageVo.setUpdateTime(codingRule.getUpdateTime());
            codingRulePageVo.setUpdateUser(codingRule.getUpdateUser());
        }

        UserUtil.assignmentNickName(codingRulePageVoList, CodingRulePageVo::getUpdateUser, CodingRulePageVo::setUpdateUserName);

        return page;
    }

    @Override
    public void edit(CodingRuleDto codingRuleDto) {
        codingRuleDto.setRuleJson(JSON.toJSONString(codingRuleDto.getRuleVoList()));
        this.saveOrUpdate(codingRuleDto);
    }

    /**
     * 生成编码
     *
     * @param key        编码key
     * @param customerId 客户id
     * @return 生成的编码
     */
    @Override
    public String createCode(String key, Long customerId) {

        StringBuilder codeBuilder = new StringBuilder();

        CustomerCodeAndCountryId customerCodeAndCountryId = null;
        Integer autoNum = null;
        String countryCode = null;
        String userCode = null;
        Date data = null;

        List<RuleVo> ruleVoList = getRuleVoList(key);
        for (RuleVo ruleVo : ruleVoList) {
            Integer ruleType = ruleVo.getRuleType();
            RuleTypeEnum ruleTypeEnum = RuleTypeEnum.getRuleTypeEnum(ruleType);

            switch (ruleTypeEnum) {
                case CUSTOMIZE:
                    codeBuilder.append(ruleVo.getValue());
                    break;
                case COUNTRY_CODE:
                    if (customerCodeAndCountryId == null) {
                        customerCodeAndCountryId = codingRuleCustomerService.getCustomerCodeAndCountryId(customerId);
                    }
                    if (countryCode == null) {
                        countryCode = getCountryCode(customerCodeAndCountryId.getCountryId());
                    }
                    codeBuilder.append(countryCode);
                    break;
                case SALESMAN_CODE:
                    if (userCode == null) {
                        userCode = getUserCode();
                    }
                    codeBuilder.append(userCode);
                    break;
                case CUSTOMER_CODE:
                    if (customerCodeAndCountryId == null) {
                        customerCodeAndCountryId = codingRuleCustomerService.getCustomerCodeAndCountryId(customerId);
                    }
                    codeBuilder.append(customerCodeAndCountryId.getCustomerCode());
                    break;
                case AUTOINCREMENT:
                    if (autoNum == null) {
                        autoNum = getAutoCode(key);
                    }
                    String value = ruleVo.getValue();
                    codeBuilder.append(autoGenericCode(value, autoNum));
                    break;
                case DATE_FORMAT:
                    String dataFormat = ruleVo.getValue();
                    try {
                        if (data == null) {
                            data = new Date();
                        }
                        String format = DateUtil.format(data, dataFormat);
                        codeBuilder.append(format);
                    } catch (Exception e) {
                        throw new ServiceException("生成编码配置日期生成格式错误");
                    }
                    break;
            }
        }

        return codeBuilder.toString();
    }

    private Integer getAutoCode(String key) {
        CodingRuleAuto codingRuleAuto = codingRuleAutoService.getOne(q -> q.eq(CodingRuleAuto::getKey, key));
        if (codingRuleAuto == null) {
            codingRuleAuto = new CodingRuleAuto();
            codingRuleAuto.setKey(key);
            codingRuleAuto.setNum(1);
            codingRuleAutoService.save(codingRuleAuto);
            return 1;
        }

        codingRuleAuto.setNum(codingRuleAuto.getNum() + 1);
        codingRuleAutoService.updateById(codingRuleAuto);
        return codingRuleAuto.getNum();
    }


    private int getTempIndex(int startIndex, int endIndex, int tempIndex,
                             List<CodingRulePageVo> codingRulePageVoList,
                             List<String> keyList,
                             CodingRuleEnum codingRuleEnum) {

        if (tempIndex >= startIndex && tempIndex < endIndex) {
            CodingRulePageVo codingRulePageVo = new CodingRulePageVo();
            codingRulePageVo.setCodingKey(codingRuleEnum.getKey());
            codingRulePageVo.setCodingName(codingRuleEnum.getName());
            codingRulePageVo.setRuleVoList(codingRuleEnum.getDefaultRuleVoList());
            codingRulePageVoList.add(codingRulePageVo);
            keyList.add(codingRuleEnum.getKey());
        }

        return ++tempIndex;
    }

    private List<RuleVo> getRuleVoList(String key) {
        CodingRule codingRule = getOne(q -> q.eq(CodingRule::getCodingKey, key));

        if (codingRule != null) {
            List<RuleVo> ruleVoList = JSON.parseArray(codingRule.getRuleJson(), RuleVo.class);
            if (ruleVoList.size() == 0) {
                throw new ServiceException("编码生成规则为空");
            }
            return ruleVoList;
        }
        return CodingRuleEnum.getDefaultRuleVoList(key);
    }

    private String getCountryCode(Long countryId) {
        CustomizeArea customizeArea = customizeAreaService.getOne(q -> q
                .eq(BaseIdPo::getId, countryId)
                .eq(CustomizeArea::getLevelCode, 1));

        if (customizeArea == null) {
            throw new ServiceException("国家为空");
        }

        return customizeArea.getCode();
    }


    /**
     * 获取业务员编码
     */
    private String getUserCode() {
        SysUser sysUser = sysUserService.getById(SecurityUtils.getUserId());
        String userCode = sysUser.getUserCode();
        if (StrUtil.isBlank(userCode)) {
            throw new ServiceException("业务原代码未配置，生成编码失败");
        }
        return userCode;
    }

    /**
     * 不够位数的在前面补0，保留num的长度位数字
     */
    private static String autoGenericCode(Object length, Integer codeNum) {
        Integer integer = Convert.toInt(length);
        if (integer == null) {
            throw new ServiceException("自定义编码长度不为数字");
        }

        return String.format("%0" + integer + "d", codeNum + 1);
    }

}
