package com.kcim.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.CommonUtil;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.CostChildColumn;
import com.kcim.dao.model.CostColumn;
import com.kcim.dao.repository.CostChildColumnRepository;
import com.kcim.dao.repository.CostColumnRepository;
import com.kcim.service.CenterService;
import com.kcim.service.CostColumnService;
import com.kcim.vo.DictDataVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.kcim.common.constants.Constant.REPORT_COLUMN_TYPE;


@Service("costColumnService")
@AllArgsConstructor
@Slf4j
public class CostColumnServiceImpl  implements CostColumnService {

    CostColumnRepository repository;

    CenterService centerService;

    CostChildColumnRepository childColumnRepository;

    /**
     * 报表管理-报表列管理-获取
     *
     * @param current    当前页
     * @param pageSize   页容量
     * @param columnName 列名称
     * @param columnType 列类型
     * @return 列表数据
     */
    @Override
    public Object getColumnList(Integer current, Integer pageSize, String columnName, String columnType) {
        Page<CostColumn> page = repository.getPage(current, pageSize, columnName, columnType);
        List<CostColumn> records = page.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return new PageUtils(new ArrayList<>(),NumberConstant.ZERO,pageSize,current);
        }
        List<Long> collect = records.stream().map(CostColumn::getCode).collect(Collectors.toList());
        List<CostChildColumn> childColumns = childColumnRepository.getByParentCode(collect);
        Map<Long, List<CostChildColumn>> childColumn = new HashMap<>();
        if(!CollectionUtils.isEmpty(childColumns)){
            childColumn = childColumns.stream().collect(Collectors.groupingBy(CostChildColumn::getParentColumnCode));
        }
        List<DictDataVo> dictDataVos = getColumnType();
        Map<String,String> map = dictDataVos.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getName, (a, b) -> b));
        for(CostColumn column:records){
            if(!CollectionUtils.isEmpty(map)){
                column.setTypeName(map.get(column.getType()));
                column.setDataTypeName(setDataTypeName(column.getDataType()));
            }
            if(!CollectionUtils.isEmpty(childColumn)){
                column.setChildColumnList(childColumn.get(column.getCode()));
            }
        }
        return new PageUtils(records, Math.toIntExact(page.getTotal()),pageSize,current);
    }
    private String setDataTypeName(Integer dataType) {
//        数据类型 0 未知 1 文本  3 数值 2百分比
        if(dataType !=null ){
            if(dataType.equals(NumberConstant.ONE)){
                return "文本";
            }  else if (dataType.equals(NumberConstant.THREE)) {
                return "数值";
            } else if (dataType.equals(NumberConstant.TWO)) {
                return "百分比";
            }else {
                return "未知";
            }
        }else {
            return "未知";
        }
    }

    /**
     * 获取报表列字典
     *
     * @return 列字典
     */
    @Override
    public List<DictDataVo> getColumnType() {
        DictDataVo centerDict = centerService.getDict(REPORT_COLUMN_TYPE);
        return centerDict.getDataVoList();
    }

    /**
     * 新增报表列
     * @param column 报表列对象
     */
    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public void addColumn(CostColumn column) {
//        check(column);
        column.setHospId(UserContext.getCurrentLoginHospId());
        column.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        column.setCreateTime(new Date());
        column.setCode(repository.getCode());
        if(column.getDataSource() != null && column.getDataSource().equals(NumberConstant.ONE)){
            checkCalcFormula(column.getFormula());
        }
        repository.save(column);
    }



    /**
     * 编辑报表列
     *
     * @param column 报表列对象
     */
    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public void editColumn(CostColumn column) {
        if(column.getId()==null){
            throw new CostException("编辑时，主键必传");
        }
        CostColumn costColumn = repository.getById(column.getId());
        BeanUtil.convertObj(column,costColumn);
        costColumn.setUpdateTime(new Date());
        costColumn.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        costColumn.setHospId(UserContext.getCurrentLoginHospId());
        if(column.getDataSource() != null && column.getDataSource().equals(NumberConstant.ONE)){
            checkCalcFormula(column.getFormula());
        }
        repository.updateById(costColumn);
    }

    /**
     * 删除报表列
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public void deleteColumn(Integer id) {
        repository.deleteColumn(id);
    }

    /**
     * 获取除当前报表列外的所有报表列
     * @param columnCode 当前报表列代码
     * @return 报表列
     */
    @Override
    public Object getChildColumnList(Long columnCode) {
        return repository.getChildColumnList(columnCode);
    }

    private void checkCalcFormula(String calcFormula) {
        // 校验公式不存在单独的'[' 或 ']'，中括号未闭合
        if (StrUtil.isBlank(calcFormula)) {
            throw new CostException("计算公式未传递");
        }
        boolean flag = CommonUtil.whetherStringClose(calcFormula);
        if (!flag) {
            throw new CostException("计算公式错误，英文中括号未正确闭合");
        }
        // 以下校验公式编号是否合法
        Pattern pattern = Pattern.compile("(\\[[^\\]]*\\])");
        Matcher m = pattern.matcher(calcFormula);
        List<String> list = new ArrayList<>();
        while (m.find()) {
            if (StrUtil.isNotBlank(m.group())) {
                list.add(m.group());
            }
        }
        if (list.size() == 0) {
            throw new CostException("计算公式错误，请使用英文输入状态下括号标识");
        }
        // 校验所有编号不是同一个
        Set<String> set = new HashSet<>(list);
        if (set.size() != list.size()) {
            throw new CostException("公式中编号有重复");
        }

        // 校验编号是否存在
        list.forEach(i -> {
            String sub = StrUtil.sub(i, i.indexOf("[") + 1, i.lastIndexOf("]"));
            CostColumn one = repository.getByCode(sub);
            if (Objects.isNull(one)) {
                throw new CostException("计算公式中编号不存在");
            }
        });
    }
}