package com.patzn.lims.res.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.patzn.lims.common.CodeKeyUtils;
import com.patzn.lims.common.CommonConstants;
import com.patzn.lims.core.api.PtAssert;
import com.patzn.lims.core.bean.BaseEntity;
import com.patzn.lims.core.toolkit.FreemarkerUtils;
import com.patzn.lims.core.web.BaseServiceImpl;
import com.patzn.lims.res.entity.LmsCodeRule;
import com.patzn.lims.res.entity.LmsCodeRuleRecord;
import com.patzn.lims.res.enums.CodeTypeEnum;
import com.patzn.lims.common.StringHandleUtils;
import com.patzn.lims.res.mapper.LmsCodeRuleMapper;
import com.patzn.lims.res.service.ILmsBaseDictService;
import com.patzn.lims.res.service.ILmsCodeRuleRecordService;
import com.patzn.lims.res.service.ILmsCodeRuleService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;

/**
 * <p>
 * 编号规则 服务实现类
 * </p>
 *
 * @author patzn
 * @since 2018-04-11
 */
@Service
public class LmsCodeRuleServiceImpl extends BaseServiceImpl<LmsCodeRuleMapper, LmsCodeRule> implements ILmsCodeRuleService {

    @Autowired
    private ILmsBaseDictService baseDictService;
    @Autowired
    private ILmsCodeRuleRecordService codeRuleRecordService;


    @Override
    public Page<LmsCodeRule> page(Page<LmsCodeRule> page, LmsCodeRule lmsCodeRule) {
        QueryWrapper wrapper = Wrappers.<LmsCodeRule>query(lmsCodeRule);
        return page(page, wrapper);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String getKey(CodeTypeEnum codeTypeEnum, BaseEntity entity) {
        return getKey((Integer) codeTypeEnum.getValue(), codeTypeEnum.getDisplay(), entity);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String getKey(Integer codeType, String codeName, BaseEntity entity) {

        LmsCodeRule codeRule = super.getOne(Wrappers.query(new LmsCodeRule()).eq("type", codeType).last("LIMIT 1"));

        if (null == codeRule) {
            PtAssert.fail(codeName + "不存在请配置规则");
        }
        StringBuffer key = new StringBuffer();
        // 前缀规则
        if (null != codeRule.getPre()) {
            key.append(codeRule.getPre());
        }
        String[] rules = codeRule.getRule().split("&");
        Map model = new HashMap(2);
        model.put("et", entity);
        model.put("kt", new CodeKeyUtils());
        for (String rule : rules) {
            // 日期规则
            if (rule.contains("@")) {
                if ("@YY".equalsIgnoreCase(rule)) {
                    key.append(new DateTime().toString("YYYY").substring(2));
                } else {
                    key.append(new DateTime().toString(rule.substring(1)));
                }
            } else if (rule.contains("%")) {
                String value;
                String myRules = rule.replace("%", "").replace("{", "").replace("}", "");
                String[] dictArr = myRules.split("\\.");
                if (null != dictArr[1]) {
                    value = StringHandleUtils.getFieldValueByFieldName(dictArr[1], model.get("et"));
                    key.append(value);
                }
            }
            // 字典规则【 分类?属性 】  监测类别?${et.testType}
            else if (rule.contains("?")) {
                try {
                    String[] dictArr = rule.split("\\?");

                    String value = "";
                    if (null != dictArr[1] && dictArr[1].contains("$")) {
                        String attributes = StringHandleUtils.getAttributesFromCodeRules(dictArr[1]);
                        value = StringHandleUtils.getFieldValueByFieldName(attributes, model.get("et"));
                    }
                    if (!"".equalsIgnoreCase(value)) {
                        key.append(baseDictService.getCode(dictArr[0],
                                FreemarkerUtils.process(dictArr[1], model)));
                    }
                } catch (Exception e) {
                    PtAssert.fail("编号生成异常，请联系管理员");
                }
            }
            // 属性规则
            else if (rule.contains("$")) {
                try {
                    key.append(FreemarkerUtils.process(rule, model));
                } catch (Exception e) {
                    PtAssert.fail("编号生成异常，请联系管理员");
                }
            }
            // SN 序列号
            else if ("SN".equals(rule)) {
                key.append(CommonConstants.SN);
            }
            // 原样输出
            else {
                key.append(rule);
            }
        }
        // SN 规则
        String sn="";
        if(null==codeRule.getContinueSn()||0==codeRule.getContinueSn()){
            sn= CodeKeyUtils.getSn(codeRuleRecordService.getNextSn(codeRule, key.toString()), codeRule.getLength());
        }else{
            sn= CodeKeyUtils.getSn(codeRule.getSn()+1, codeRule.getLength());
        }


        // 更新规则序列号
        nextSn(codeRule.getId(), codeRule.getSn());
        return key.toString().replaceAll(CommonConstants.SN, sn);
    }


    @Override
    public int getKeySnLength(CodeTypeEnum codeTypeEnum, BaseEntity entity) {
        LmsCodeRule lmsCodeRule = super.getOne(Wrappers.query(new LmsCodeRule()).eq("type", codeTypeEnum).last("LIMIT 1"));
        if (null == lmsCodeRule || null == lmsCodeRule.getLength()) {
            return 0;
        }
        return lmsCodeRule.getLength();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean initBaseCodeRule(Long companyId) {
        List<LmsCodeRule> crList = baseMapper.selectCodeRuleList();
        if (CollectionUtils.isEmpty(crList)) {
            return true;
        }
        super.remove(Wrappers.query(new LmsCodeRule()).eq("company_id", companyId));
        return super.saveBatch(crList.stream().map(e -> {
            e.setId(null);
            e.setCompanyId(companyId);
            return e;
        }).collect(toList()));
    }


    /**
     * <p>
     * 下一个 SN
     * </p>
     *
     * @param id 主键 ID
     * @param sn 序列号
     * @return
     */
    private int nextSn(long id, int sn) {
        int next = sn + 1;
        LmsCodeRule cr = new LmsCodeRule();
        cr.setSn(next);
        if (!super.update(cr, Wrappers.query(new LmsCodeRule()).eq("id", id).eq("sn", sn))) {
            // 重复递归寻找可用序列
            next = nextSn(id, next);
        }
        return next;
    }


    @Override
    public boolean updateById(LmsCodeRule entity) {
        if (null == entity || null == entity.getId()) {
            return false;
        }
        LmsCodeRule lcr = super.getById(entity.getId());
        if (null == lcr) {
            return false;
        }
        return super.updateById(entity);
    }

    @Override
    public LmsCodeRule getCodeRule(CodeTypeEnum codeType) {
        QueryWrapper wrapper = Wrappers.query(new LmsCodeRule().setType(codeType));
        List<LmsCodeRule> rules = super.list(wrapper);
        if (CollectionUtils.isNotEmpty(rules)) {
            return rules.get(0);
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateCodeRule(LmsCodeRule lmsCodeRule) {
        if (StringUtils.isEmpty(lmsCodeRule.getPre())) {
            updatePreToNull(lmsCodeRule);
        }
        return super.updateById(lmsCodeRule);
    }

    @Override
    public Page<LmsCodeRuleRecord> pageRecord(Page<LmsCodeRuleRecord> page, LmsCodeRuleRecord record) {
        PtAssert.fail(null == record.getCodeRuleId(), "编号规则id不能为空");
        QueryWrapper wrapper = Wrappers.query(new LmsCodeRule()).eq("code_rule_id", record.getCodeRuleId());
        if (StringUtils.isNotEmpty(record.getVary())) {
            wrapper.like("vary", record.getVary());
            record.setVary(null);
        }
        wrapper.orderBy(true,true,"ctime", false);
        return codeRuleRecordService.page(page, wrapper);
    }

    @Override
    public boolean editRecord(Long id, Integer sn) {
        PtAssert.fail(null == id || null == sn, "数据不能为空");
        return codeRuleRecordService.update(new LmsCodeRuleRecord().setSn(sn),  Wrappers.<LmsCodeRuleRecord>query().eq("id", id));
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    int updatePreToNull(LmsCodeRule lmsCodeRule) {
        return baseMapper.updatePreToNull(lmsCodeRule);
    }

}
