package com.dayou.interceptor;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类说明：默认分页拦截器
 *
 * @author: wucl
 * @since: 2022/11/28
 * created with IntelliJ IDEA.
 */
@Setter
@Accessors(chain = true)
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Slf4j
public class DefaultPageIntecptor extends PaginationInterceptor {

    protected static final String DEFAULT_ORDER_CLOMUN = "id";

    /**
     * 尽可能的找出默认排序字段
     * 查询SQL拼接Order By
     * 优先取别名id 没取到再取id  如果已有排序 就不传
     *
     * @param originalSql 需要拼接的SQL
     * @param page        page对象
     * @return ignore
     */
    @Override
    public String concatOrderBy(String originalSql, IPage<?> page) {
        if (CollectionUtils.isEmpty(page.orders())) {
            String defalutOrder = DEFAULT_ORDER_CLOMUN;
            try {
                Select selectStatement = (Select) CCJSqlParserUtil.parse(originalSql);
                if (selectStatement.getSelectBody() instanceof PlainSelect) {
                    PlainSelect plainSelect = (PlainSelect) selectStatement.getSelectBody();
                    List<OrderByElement> orderByElements = plainSelect.getOrderByElements();
                    FromItem fromItem = plainSelect.getFromItem();
                    String oneAlis = getOneAlis(Lists.newArrayList(fromItem));
                    String otherAlis = null;
                    List<Join> joins = plainSelect.getJoins();
                    if (CollUtil.isNotEmpty(joins)) {
                        List<FromItem> collect = joins.stream().map(Join::getRightItem).collect(Collectors.toList());
                        otherAlis = getOneAlis(collect);
                    }
                    String SPLITER = ".";
                    defalutOrder = oneAlis == null ? (otherAlis == null ? DEFAULT_ORDER_CLOMUN : otherAlis + SPLITER + DEFAULT_ORDER_CLOMUN)
                            : (oneAlis + SPLITER + DEFAULT_ORDER_CLOMUN);
                    if (CollUtil.isNotEmpty(orderByElements)) {
                        //sql里已有排序 就不添加默认排序
                        defalutOrder = null;
                    }
                }
            } catch (Exception e) {
                defalutOrder = DEFAULT_ORDER_CLOMUN;
            }

            if (page instanceof Page && defalutOrder != null) {
                List<OrderItem> item = new ArrayList<>();
                OrderItem defaultOrderItem = new OrderItem();
                //客户端不传排序的时候 全局按照id  降序排列  这里暂时写死id
                defaultOrderItem.setColumn(defalutOrder);
                defaultOrderItem.setAsc(false);
                item.add(defaultOrderItem);
                ((Page<?>) page).addOrder(item);
            }
        }
        return super.concatOrderBy(originalSql, page);
    }

    /**
     * 获取一个sql里有效的别名
     *
     * @param fromItems
     * @return
     */
    protected static String getOneAlis(List<? extends FromItem> fromItems) {
        if (CollUtil.isNotEmpty(fromItems)) {
            for (FromItem fromItem : fromItems) {
                if (fromItem == null) {
                    continue;
                }
                Alias alias = fromItem.getAlias();
                if (alias != null && StrUtil.isNotBlank(alias.getName())) {
                    return alias.getName();
                }
            }
        }
        return null;
    }

}
