package com.platform.config;

import com.baomidou.mybatisplus.plugins.parser.tenant.TenantSqlParser;
import com.platform.modules.live.utils.PlatformTenantProperties;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author TONG
 * 2019/11/11 10:43
 **/
public class MybatisTenantParser extends TenantSqlParser {
    Logger logger = LoggerFactory.getLogger(MybatisTenantParser.class);

    private PlatformTenantProperties tenantProperties;

    public MybatisTenantParser(PlatformTenantProperties tenantProperties) {
        this.tenantProperties = tenantProperties;
    }
    /**
     * 目前无法处理多租户的字段加上表别名
     *
     * @param expression
     * @param table
     * @return
     */
    protected Expression processTableAlias(Expression expression, Table table) {
        return expression;
    }

    /**
     * 默认是按 tenant_id=1 按等于条件追加
     *
     * @param currentExpression 现有的条件：比如你原来的sql查询条件
     * @param table
     * @return
     */
    @Override
    protected Expression builderExpression(Expression currentExpression, Table table) {
//        if (this.getTenantHandler().doTableFilter(table.getName())) {
//            return currentExpression;
//        }

        final Expression tenantExpression = this.getTenantHandler().getTenantId();
        Expression appendExpression;
        if (tenantExpression == null) {
            return currentExpression;
        }
        logger.info("{} 添加租户过滤 tenantId {}", table, tenantExpression.toString());
        if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) {
            appendExpression = new EqualsTo();
            ((EqualsTo) appendExpression).setLeftExpression(this.getAliasColumn(table));
            ((EqualsTo) appendExpression).setRightExpression(tenantExpression);
        } else {
            appendExpression = processTableAlias(tenantExpression, table);
        }
        if (currentExpression == null) {
            return appendExpression;
        }
        if (currentExpression instanceof BinaryExpression) {
            BinaryExpression binaryExpression = (BinaryExpression) currentExpression;
            if (binaryExpression.getLeftExpression() instanceof FromItem) {
                processFromItem((FromItem) binaryExpression.getLeftExpression());
            }
            if (binaryExpression.getRightExpression() instanceof FromItem) {
                processFromItem((FromItem) binaryExpression.getRightExpression());
            }
        } else if (currentExpression instanceof InExpression) {
            InExpression inExp = (InExpression) currentExpression;
            ItemsList rightItems = inExp.getRightItemsList();
            if (rightItems instanceof SubSelect) {
                processSelectBody(((SubSelect) rightItems).getSelectBody());
            }
        }
        if (currentExpression instanceof OrExpression) {
            return new AndExpression(new Parenthesis(currentExpression), appendExpression);
        } else {
            return new AndExpression(currentExpression, appendExpression);
        }
    }

    @Override
    protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) {
        FromItem fromItem = plainSelect.getFromItem();
        if (fromItem instanceof Table) {
            Table fromTable = (Table) fromItem;
            if (this.getTenantHandler().doTableFilter(fromTable.getName()) || isSupserTenant()) {
                return;
            }
            plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable));
            if (addColumn) {
                plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getTenantHandler().getTenantIdColumn())));
            }
        } else {
            processFromItem(fromItem);
        }
        // 是否处理join？？？？？？
        List<Join> joins = plainSelect.getJoins();
        if (joins != null && joins.size() > 0) {
            joins.forEach(j -> {
                processJoin(j);
                processFromItem(j.getRightItem());
            });
        }
    }

    @Override
    public void processInsert(Insert insert) {

        if (this.getTenantHandler().doTableFilter(insert.getTable().getName()) || tenantProperties.getTableName().equals(insert.getTable().getName())) {
            // 过滤退出执行
            return;
        }
        List<Column> columns = insert.getColumns();
        String tenantIdColumn = this.getTenantHandler().getTenantIdColumn();
        for (Column column : columns) {
            if (column.getColumnName().equals(tenantIdColumn)) {
                // insert 中已经包含退出执行
                return;
            }
        }
        super.processInsert(insert);
    }

    /**
     * <p>
     * update 语句处理
     * </p>
     */
    @Override
    public void processUpdate(Update update) {
        if (isSupserTenant()) {
            return;
        }
        super.processUpdate(update);
    }
    @Override
    public void processDelete(Delete delete) {
        if (isSupserTenant()) {
            return;
        }
        super.processDelete(delete);
    }

    /**
     * 是否管理员或超级租户
     * @return
     */
    private boolean isSupserTenant() {
        Expression tenantIdExpression = this.getTenantHandler().getTenantId();
        if (tenantIdExpression == null) {
            return true;
        }
        String tenantId = ((LongValue) tenantIdExpression).getStringValue();
        if (tenantId !=null && tenantId.length() > 0 && tenantProperties.getManageTenantId().equals(Long.parseLong(tenantId))) {
            return true;
        }
        return false;
    }
}
