package com.purui.prims.headless.core.utils;

import com.purui.prims.common.pojo.enums.TimeDimensionEnum;
import com.purui.prims.headless.api.pojo.Dim;
import com.purui.prims.headless.api.pojo.DimensionTimeTypeParams;
import com.purui.prims.headless.api.pojo.enums.DimensionType;
import com.purui.prims.headless.core.adaptor.db.DbAdaptor;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 系统时间维度构建工具
 * @author charlie
 * @date   2024/6/27
 */
@Slf4j
public class SysTimeDimensionBuilder {

    private static final Pattern TIME_KEYWORD_PATTERN =
        Pattern.compile("\\b(DATE|TIME|TIMESTAMP|YEAR|MONTH|DAY|HOUR|MINUTE|SECOND)\\b",
            Pattern.CASE_INSENSITIVE);

    // 加入默认统计周期（日期维度默认为天）
    public static void addSysTimeDimension(List<Dim> dims, DbAdaptor engineAdaptor) {
        log.debug("addSysTimeDimension before:{}, engineAdaptor:{}", dims, engineAdaptor);
        Dim timeDim = getTimeDim(dims);
        if (timeDim == null) {
            timeDim = Dim.getDefault();
        }
        dims.add(generateSysDayDimension(timeDim, engineAdaptor));
        dims.add(generateSysWeekDimension(timeDim, engineAdaptor));
        dims.add(generateSysMonthDimension(timeDim, engineAdaptor));
        dims.add(generateSysYearDimension(timeDim, engineAdaptor));
        log.debug("addSysTimeDimension after:{}, engineAdaptor:{}", dims, engineAdaptor);
    }

    private static Dim generateSysDayDimension(Dim timeDim, DbAdaptor engineAdaptor) {
        Dim dim = new Dim();
        dim.setBizName(TimeDimensionEnum.DAY.getName());
        dim.setType(DimensionType.time.name());
        dim.setExpr(generateTimeExpr(timeDim, TimeDimensionEnum.DAY.name().toLowerCase(), engineAdaptor));
        DimensionTimeTypeParams typeParams = new DimensionTimeTypeParams();
        typeParams.setTimeGranularity(TimeDimensionEnum.DAY.name().toLowerCase());
        typeParams.setIsPrimary(true);
        dim.setTypeParams(typeParams);
        return dim;
    }

    private static Dim generateSysWeekDimension(Dim timeDim, DbAdaptor engineAdaptor) {
        Dim dim = new Dim();
        dim.setBizName(TimeDimensionEnum.WEEK.getName());
        dim.setType(DimensionType.time.name());
        dim.setExpr(generateTimeExpr(timeDim, TimeDimensionEnum.WEEK.name().toLowerCase(), engineAdaptor));
        DimensionTimeTypeParams typeParams = new DimensionTimeTypeParams();
        typeParams.setTimeGranularity(TimeDimensionEnum.WEEK.name().toLowerCase());
        typeParams.setIsPrimary(false);
        dim.setTypeParams(typeParams);
        return dim;
    }

    private static Dim generateSysMonthDimension(Dim timeDim, DbAdaptor engineAdaptor) {
        Dim dim = new Dim();
        dim.setBizName(TimeDimensionEnum.MONTH.getName());
        dim.setType(DimensionType.time.name());
        dim.setExpr(generateTimeExpr(timeDim, TimeDimensionEnum.MONTH.name().toLowerCase(), engineAdaptor));
        DimensionTimeTypeParams typeParams = new DimensionTimeTypeParams();
        typeParams.setTimeGranularity(TimeDimensionEnum.MONTH.name().toLowerCase());
        typeParams.setIsPrimary(false);
        dim.setTypeParams(typeParams);
        return dim;
    }

    private static Dim generateSysYearDimension(Dim timeDim, DbAdaptor engineAdaptor) {
        Dim dim = new Dim();
        dim.setBizName(TimeDimensionEnum.YEAR.getName());
        dim.setType(DimensionType.time.name());
        dim.setExpr(generateTimeExpr(timeDim, TimeDimensionEnum.YEAR.name().toLowerCase(), engineAdaptor));
        DimensionTimeTypeParams typeParams = new DimensionTimeTypeParams();
        typeParams.setTimeGranularity(TimeDimensionEnum.YEAR.name().toLowerCase());
        typeParams.setIsPrimary(false);
        dim.setTypeParams(typeParams);
        return dim;
    }

    private static boolean containsTimeKeyword(String fieldName) {
        Matcher matcher = TIME_KEYWORD_PATTERN.matcher(fieldName);
        return matcher.find();
    }

    private static String generateTimeExpr(Dim timeDim, String dateType, DbAdaptor engineAdaptor) {
        String bizName = timeDim.getBizName();
        String dateFormat = timeDim.getDateFormat();
        if (containsTimeKeyword(bizName)) {
            String bizNameWithBackticks = String.format("`%s`", bizName);
            return engineAdaptor.getDateFormat(dateType, dateFormat, bizNameWithBackticks);
        } else {
            return engineAdaptor.getDateFormat(dateType, dateFormat, timeDim.getFieldName());
        }
    }

    private static Dim getTimeDim(List<Dim> timeDims) {
        for (Dim dim : timeDims) {
            if (dim.getType().equalsIgnoreCase(DimensionType.time.name())) {
                return dim;
            }
        }
        return null;
    }

}
