package com.jy.framework.mybatis.join;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class QueryCondition extends AbstractSql {

    private final String template;
    private final AbstractSql column;
    private final Object param;
    private final List<QueryConditionConnect> queryConditionConnectList = new ArrayList<>();

    private boolean exist = true;

    /**
     * and关联
     */
    public QueryCondition and(QueryCondition queryCondition) {
        queryConditionConnectList.add(new QueryConditionConnect(SqlConstant.AND, queryCondition));
        return this;
    }

    /**
     * or关联
     */
    public QueryCondition or(QueryCondition queryCondition) {
        queryConditionConnectList.add(new QueryConditionConnect(SqlConstant.OR, queryCondition));
        return this;
    }

    /**
     * 设置此运算是否存在
     */
    public QueryCondition exist(boolean exist) {
        this.exist = exist;
        return this;
    }

    @Override
    protected String format() {
        String connectStr = queryConditionConnectList.stream().map(AbstractSql::format).collect(Collectors.joining());

        if (ObjectUtil.isEmpty(param) || !exist) {

            if (ObjectUtil.isEmpty(connectStr)) {
                return StringPool.EMPTY;
            }

            if (connectStr.startsWith(SqlConstant.AND)) {
                connectStr = connectStr.substring(SqlConstant.AND.length());
            } else if (connectStr.startsWith(SqlConstant.OR)) {
                connectStr = connectStr.substring(SqlConstant.OR.length());
            } else {
                return StringPool.EMPTY;
            }

            if ((connectStr.contains(SqlConstant.AND) || connectStr.contains(SqlConstant.OR))
                    && !connectStr.startsWith(StringPool.LEFT_BRACKET)
                    && !connectStr.endsWith(StringPool.RIGHT_BRACKET)) {
                return StringPool.LEFT_BRACKET + connectStr + StringPool.RIGHT_BRACKET;
            }

            return connectStr;
        }

        String sql = column.format() + switch (template) {
            case SqlConstant.IN, SqlConstant.NOT_IN -> {
                String value = Arrays.stream((Object[]) param)
                        .map(SqlContext::formatValue)
                        .collect(Collectors.joining(StringPool.COMMA));

                yield template.formatted(value);
            }

            case SqlConstant.BETWEEN, SqlConstant.NOT_BETWEEN -> {
                Object[] params = (Object[]) param;
                yield template.formatted(SqlContext.formatValue(params[0]), SqlContext.formatValue(params[1]));
            }

            case SqlConstant.IS_NULL, SqlConstant.IS_NOT_NULL -> template;

            default -> template.formatted(SqlContext.formatValue(param));
        };

        if (ObjectUtil.isEmpty(connectStr)) {
            return sql;
        }

        return StringPool.LEFT_BRACKET + sql + connectStr + StringPool.RIGHT_BRACKET;
    }

}
