package me.qwq.doghouse.pojo.dto;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

import org.springframework.web.util.UriComponentsBuilder;

import jakarta.servlet.http.HttpSession;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.qwq.doghouse.component.PostTypeComponent;
import me.qwq.doghouse.entity.Cate;
import me.qwq.doghouse.entity.Meta;
import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.entity.Tag;
import me.qwq.doghouse.enums.MetaTypeEnum;
import me.qwq.doghouse.enums.PostTypeEnum;
import me.qwq.doghouse.interfaces.IPostTypeConfig;
import me.qwq.doghouse.pojo.bo.PostPassJar;
import me.qwq.doghouse.util.SpringContextHolder;

import com.github.yulichang.wrapper.MPJLambdaWrapper;

/**
 * 前台分页查询
 */
@Accessors(chain = true)
public class PageQuery<T> implements Serializable {

    
    private static final long serialVersionUID = -3222557144229477995L;
    
    public static final String TAG = "tag";
    public static final String CATEGORY = "category";
    public static final String SEARCH = "search";
    
    
    private static final String TAG_FORMAT = "标签「%s」下的 %s";
    private static final String CATEGORY_FORMAT = "分类「%s」下的 %s";
    private static final String SEARCH_FORMAT = "包含关键字「%s」的 %s";

    private static final String BASE_TITLE_FORMAT = "第 %d 页";
    private static final String CONNECTOR = " - ";

    private static PostTypeComponent postTypeComponent;
    
    @Getter
    private T query;

    @Getter
    @Setter
    private List<Post> records;

    @Getter
    @Setter
    private Long current;

    @Getter
    @Setter
    private Long pages;

    @Getter
    @Setter
    private Long size;

    @Getter
    @Setter
    private Long total;

    @Setter
    private String title;
    
    @Getter
    @Setter
    private PostTypeEnum postType;
    
    public PageQuery(PostTypeEnum postType) {
        this.postType = postType;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(query, current, size, postType);
    }
    
    /**
     * 设置分页查询结果
     * @param page
     * @return
     */
    public PageQuery<T> setResult(IPage<Post> page) {
        records = page.getRecords();
        current = page.getCurrent();
        pages = page.getPages();
        size = page.getSize();
        total = page.getTotal();
        return this;
    }
    
    /**
     * 转换为 Page 查询条件
     * @return
     */
    public Page<Post> toPage() {
        return new Page<Post>(current, size);
    }
    
    /**
     * 直接设置完整查询类型
     * @param query
     * @return
     */
    public PageQuery<T> setQuery(T query) {
        assert query instanceof String || query instanceof Tag || query instanceof Cate || query instanceof Meta;
        this.query = (T)query;
        return this;
    }
    
    /**
     * 获取查询类型
     * @return
     */
    public String getType() {
        if (query == null) {
            return null;
        }
        else if (query.getClass() == Tag.class) {
            return TAG;
        }
        else if (query.getClass() == Cate.class) {
            return CATEGORY;
        }
        else if (query.getClass() == String.class) {
            return SEARCH;
        }
        else if (query.getClass() == Meta.class) {
            Meta meta = (Meta)query;
            return meta.getType() == MetaTypeEnum.TAG ? TAG : CATEGORY;
        }
        else return null;
    }
    
    /**
     * 当且仅当查询完成后再调用该方法
     * @return
     */
    public String getTitle() {
        if (title != null) {
            return title;
        }
        String baseTitle = String.format(BASE_TITLE_FORMAT, getCurrent());

        String type = getType();
        if (type == null) {
            return baseTitle;
        }
        switch (type) {
        case TAG:
            baseTitle += CONNECTOR + String.format(TAG_FORMAT, ((Tag)query).getName(), getPostType().getNote());
            break;
        case CATEGORY:
            baseTitle += CONNECTOR + String.format(CATEGORY_FORMAT, ((Cate)query).getName(), getPostType().getNote());
            break;
        case SEARCH:
            baseTitle += CONNECTOR + String.format(SEARCH_FORMAT, query, getPostType().getNote());
            break;
        }
        return baseTitle;
    }
    
    /**
     * 获取友好名称，用于前端某些位置直接显示
     * @return
     */
    public String getFriendlyName() {
        String type = getType();
        if (type == null) {
            return null;
        }
        switch (type) {
        case TAG:
        case CATEGORY:
            return ((Meta)query).getFriendlyName();
        case SEARCH:
            return (String)query;
        default:
            return null;
        }
    }

    /**
     * 获取显示名称，用于前端某些位置直接显示
     * @return
     */
    public String getDisplayName() {
        String type = getType();
        if (type == null) {
            return null;
        }
        switch (type) {
        case TAG:
        case CATEGORY:
            return ((Meta)query).getName();
        case SEARCH:
            return (String)query;
        default:
            return null;
        }
    }
    
    /**
     * 获取分页链接前缀
     * @return
     */
    public String getPaginationPrefix() {
        String type = getType(), friendlyName = getFriendlyName();
        IPostTypeConfig<?> config = getPostTypeComponent().getPostTypeConfig(getPostType());
        UriComponentsBuilder builder = UriComponentsBuilder.fromPath(config.getMappingPrefix());
        if (type == null) {
            builder.pathSegment("page");
        }
        else {
            builder.pathSegment(type, friendlyName);
        }
        return new StringBuilder().append(builder.build()).append('/').toString();
    }
    
    /**
     * 根据提供的 query 实体，设置查询 Wrapper
     * @param wrapper
     * @return
     */
    public MPJLambdaWrapper<Post> setQueryCondition(MPJLambdaWrapper<Post> wrapper) {
        String type = getType(), friendlyName = getFriendlyName();
        return wrapper
                .eq(TAG.equals(type), Tag::getFriendlyName, friendlyName)
                .eq(CATEGORY.equals(type), Cate::getFriendlyName, friendlyName)
                .and(SEARCH.equals(type), i -> i
                        .like(Post::getPostTitle, friendlyName)
                        .or()
                        .like(Post::getPostContent, friendlyName));
    }
    
    /**
     * 根据 session 更新文章加密情况
     * @param session
     * @return
     */
    public PageQuery<T> checkPassword(HttpSession session) {
        for (Post p : getRecords()) {
            PostPassJar.validFromSession(session, p);
        }
        return this;
    }
    
    private static PostTypeComponent getPostTypeComponent() {
        if (postTypeComponent == null) {
            postTypeComponent = SpringContextHolder.getBean(PostTypeComponent.class);
        }
        return postTypeComponent;
    }


}
