package com.jy.framework.mybatis.join;


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

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

@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class Sql<T> extends AbstractSql {

    protected final Class<T> resultType;

    protected final List<AbstractSql> selectList = new ArrayList<>();
    protected final List<ConnectTable> tableList = new ArrayList<>();
    protected final List<AbstractSql> whereList = new ArrayList<>();
    protected final List<AbstractSql> groupByList = new ArrayList<>();
    protected final List<AbstractSql> orderByList = new ArrayList<>();
    protected final List<AbstractSql> sqlList = new ArrayList<>();

    protected Boolean deleted = false;
    protected Boolean distinct = false;
    protected String limit = StringPool.EMPTY;
    protected String unionType = StrUtil.EMPTY;

    /**
     * 创建sql查询
     */
    public static <TEMP> Sql<TEMP> create(Class<TEMP> resultType) {
        return new Sql<>(resultType);
    }

    public static Sql<JSONObject> create() {
        return new Sql<>(JSONObject.class);
    }

    /**
     * 忽略查询逻辑删除
     */
    public Sql<T> deletedIgnore() {
        this.deleted = null;
        return this;
    }

    /**
     * 查询已删除数据
     */
    public Sql<T> deleted() {
        this.deleted = true;
        return this;
    }

    /**
     * 查询未删除数据（默认）
     */
    public Sql<T> notDeleted() {
        this.deleted = false;
        return this;
    }

    /**
     * 去重
     */
    public Sql<T> distinct() {
        this.distinct = true;
        return this;
    }

    /**
     * 查询
     */
    public Select<T> select(AbstractSql... sqlFormats) {
        Select<T> select = new Select<>(this);
        select.select(sqlFormats);
        return select;
    }

    @Override
    protected String format() {
        dataFilter();

        StringBuilder sqlBuilder = new StringBuilder();

        // union 条件
        if (ObjectUtil.isNotEmpty(sqlList)) {
            sqlList.forEach(sqlFormat -> sqlBuilder.append(sqlFormat.format()));
        }

        if (StrUtil.isNotBlank(this.unionType) || ObjectUtil.isNotEmpty(sqlList)) {
            sqlBuilder.append(StringPool.LEFT_BRACKET);
        }

        // select
        sqlBuilder.append(SqlConstant.SELECT);

        // distinct
        if (this.distinct) {
            sqlBuilder.append(SqlConstant.DISTINCT);
        }

        // select字段
        String select = listFormatSql(this.selectList, StringPool.COMMA);
        if (StrUtil.isBlank(select)) {
            sqlBuilder.append(StringPool.ASTERISK);
        } else {
            sqlBuilder.append(select);
        }

        // from 表
        for (AbstractSql sqlFormat : this.tableList) {
            sqlBuilder.append(sqlFormat.format());
        }

        // where 条件
        String where = listFormatSql(this.whereList, SqlConstant.AND);
        if (StrUtil.isNotBlank(where)) {
            sqlBuilder.append(SqlConstant.WHERE).append(where);
        }

        // groupBy 条件
        String groupBy = listFormatSql(this.groupByList, StringPool.COMMA);
        if (StrUtil.isNotBlank(groupBy)) {
            sqlBuilder.append(SqlConstant.GROUP_BY).append(groupBy);
        }

        // orderBy 条件
        String orderBy = listFormatSql(this.orderByList, StringPool.COMMA);
        if (StrUtil.isNotBlank(orderBy)) {
            sqlBuilder.append(SqlConstant.ORDER_BY).append(orderBy);
        }

        // limit 条件
        sqlBuilder.append(this.limit);

        if (StrUtil.isNotBlank(this.unionType) || ObjectUtil.isNotEmpty(sqlList)) {
            sqlBuilder.append(StringPool.RIGHT_BRACKET);
        }

        // union 条件
        sqlBuilder.append(this.unionType);

        // 返回完整sql
        return sqlBuilder.toString();
    }

    /**
     * 数据过滤
     */
    private void dataFilter() {
        for (ConnectTable connectTable : this.tableList) {
            AbstractTable abstractTable = connectTable.getAbstractTable();
            if (abstractTable instanceof Table<?> table) {
                deletedDataFilter(connectTable.getJoinType(), table, connectTable.getQueryConditionList());
            }
        }
    }

    /**
     * 逻辑删除数据过滤
     */
    private void deletedDataFilter(String joinType, Table<?> table, List<AbstractSql> queryConditionList) {
        if (deleted == null) {
            return;
        }

        String tableDelFlag = SqlContext.getTableDelFlag(table.getName());
        if (StrUtil.isBlank(tableDelFlag)) {
            return;
        }

        QueryColumn deletedQueryColumn = new QueryColumn(table.getAlias(), tableDelFlag);
        QueryCondition deletedQueryCondition;
        if (deleted) {
            deletedQueryCondition = deletedQueryColumn.ne(0);
        } else {
            deletedQueryCondition = deletedQueryColumn.eq(0);
        }

        if (SqlConstant.FROM.equals(joinType)) {
            this.whereList.add(0, deletedQueryCondition);
        } else {
            queryConditionList.add(deletedQueryCondition);
        }
    }

    /**
     * 拼接sql片段
     */
    private String listFormatSql(List<? extends AbstractSql> list, String delimiter) {
        return list.stream()
                .filter(Objects::nonNull)
                .map(AbstractSql::format)
                .filter(StrUtil::isNotEmpty)
                .collect(Collectors.joining(delimiter));
    }

}
