package me.qwq.doghouse.controller.blog.post;


import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.component.PostTypeComponent;
import me.qwq.doghouse.controller.common.BaseController;
import me.qwq.doghouse.entity.*;
import me.qwq.doghouse.entity.config.CommentConfig;
import me.qwq.doghouse.entity.config.SiteConfig;
import me.qwq.doghouse.enums.PostTypeEnum;
import me.qwq.doghouse.exception.PageNotFoundException;
import me.qwq.doghouse.interfaces.IPostTypeConfig;
import me.qwq.doghouse.pojo.dto.PageQuery;
import me.qwq.doghouse.service.*;
import me.qwq.doghouse.service.post.AbstractPostService;
import me.qwq.doghouse.util.SpringContextHolder;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;


/**
 * 前端分页控制器, 不同 PostType 如需分页, 可继承该方法
 * @author Doghole
 */
@Controller
@Slf4j
public abstract class AbstractPaginationController<T extends IPostTypeConfig<T>, S extends AbstractPostService<S, T>> extends BaseController {

    @Autowired
    CommentService commentService;

    @Autowired
    MarkdownService markdownService;

    @Autowired
    CommentConfig commentConfig;

    @Autowired
    PostTypeComponent postTypeComponent;
    
    @Autowired
    ThemeService themeService;
    
    @Autowired
    SiteConfig siteConfig;
    
    T postTypeConfig;
    
    T getPostTypeConfig() {
        if (postTypeConfig != null) return postTypeConfig;
        ResolvableType type = ResolvableType.forClass(this.getClass()).as(AbstractPaginationController.class);
        ResolvableType iPageConfigType = type.getGeneric(0);
        @SuppressWarnings("unchecked")
        Class<T> iPageConfigClass = (Class<T>) iPageConfigType.resolve();
        postTypeConfig = SpringContextHolder.getBean(iPageConfigClass);
        return postTypeConfig;
    }
    
    PostTypeEnum getPostType() {
        return getPostTypeConfig().getPostType();
    }

    S postTypeService;
    
    S getPostTypeService() {
        if (postTypeService != null) return postTypeService;
        ResolvableType type = ResolvableType.forClass(this.getClass()).as(AbstractPaginationController.class);
        ResolvableType postServiceType = type.getGeneric(1);
        @SuppressWarnings("unchecked")
        Class<S> postServiceClass = (Class<S>) postServiceType.resolve();
        postTypeService = SpringContextHolder.getBean(postServiceClass);
        return postTypeService;
    }
    
    /**
     * 首页
     */
    @GetMapping({
        "", "/"})
    public String index() {
        
        return this.page(
                new PageQuery<>(getPostType())
                .setTitle(getPostTypeConfig().getIndexTitle()));
    }

    /**
     * 首页无查询条件
     * @param pageQuery
     * @return
     */
    @GetMapping({"/page", "/page/{current}"})
    public String indexPage(@PathVariable(name="current", required=false) Long current) {
        return page(new PageQuery<>(getPostType()).setCurrent(current));
    }

    /**
     * 分类
     */
    @GetMapping({"/category/{friendlyName}", "/category/{friendlyName}/{current}"})
    public String category(
            @PathVariable("friendlyName") String friendlyName,
            @PathVariable(name="current", required=false) Long current) {
        
        Cate cate = new Cate();
        cate.setFriendlyName(friendlyName);
        
        return this.page(new PageQuery<Cate>(getPostType())
                .setQuery(cate)
                .setCurrent(current));
    }

    /**
     * 标签
     */
    @GetMapping({"/tag/{friendlyName}", "/tag/{friendlyName}/{current}"})
    public String tag(
            @PathVariable("friendlyName") String friendlyName,
            @PathVariable(name="current", required=false) Long current) {
        Tag tag = new Tag();
        tag.setFriendlyName(friendlyName);
        return this.page(new PageQuery<Tag>(getPostType())
                .setQuery(tag)
                .setCurrent(current));
    }

    /**
     * 搜索，适用于伪静态的情况
     */
    @GetMapping({"/search/{keyword}", "/search/{keyword}/{page}"})
    public String search(@PathVariable("keyword") String keyword, @PathVariable(name="page", required=false) Long c) {
        
        String prefix = "redirect:" + getPostIndexPrefix();
        if (StringUtils.isEmpty(keyword)) return prefix;
        try {
            keyword = URLDecoder.decode(keyword,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.warn("搜索 keyword 编码转换失败，将跳转到首页");
            return prefix;
        }
        return this.page(new PageQuery<String>(getPostType())
                .setQuery(keyword)
                .setCurrent(c)
        );
    }
    
    /**
     * 搜索，适用于 QueryParam 的情况：.../search?keyword=xxx
     */
    @GetMapping({"/search"})
    public String search(@RequestParam(name="keyword", required=false) String keyword) {

        String prefix = "redirect:" + getPostIndexPrefix();
        if (StringUtils.isEmpty(keyword)) return prefix;
        try {
            return prefix + "search/" + URLEncoder.encode(keyword,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.warn("搜索 keyword 编码转换失败，将跳转到首页");
            return prefix;
        }
    }
    

    /**
     * 通用分页<p>
     * 注意：此处的 PageQuery 需要在调用方法内自行实例化，
     * 不能在映射方法接口上自动装填，否则经由 postService
     * 的 conditionPage 方法取缓存后，自动装填对象未被更改，
     * 会导致返回的 PageQuery 是空结果
     */
    protected String page(PageQuery<?> pageQuery) {
        
        pageQuery = getPostTypeService().conditionPage(pageQuery);
        pageQuery.checkPassword(session);

        request.setAttribute("pageQuery", pageQuery);
        setTitle(pageQuery.getTitle());
        
        request.setAttribute("canonical", siteConfig.getAddress() + "/");
        
        String targetTemplet = postTypeComponent
                .getTemplatePath(
                        getPostType(),
                        "index");
        
        return targetTemplet;
    }

    /**
     * 获取对应的路由前缀，该前缀由继承了本类的子类上的 @RequestMapping
     * 注解指定，仅取第一个路径。
     * <p>
     * <ul>
     * <li>@RequestMapping({"/", ""}) 返回 "/"
     * <li>@RequestMapping("/wiki") 返回 "/wiki/"
     * <li>@RequestMapping("/wiki/") 返回 "/wiki/"
     * <li>无注解返回 "/"
     * 
     * @param postType
     * @return
     */
    private String getPostIndexPrefix() {

        RequestMapping requestMapping = null;
        try {
            requestMapping = this.getClass().getAnnotation(RequestMapping.class);
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new PageNotFoundException();
        }
        if (requestMapping == null ||
            requestMapping.value().length == 0) {
            return "/";
        }
        String uri = requestMapping.value()[0];
        if (uri == null || uri.isBlank()) return "/";
        // 去掉前后斜杠
        uri = uri.replaceAll("^/+|/+$", "");
        // 去掉中间重复斜杠
        uri = uri.replaceAll("/+", "/");
        return "/" + uri + "/";
    }
    
    private void setTitle(String title) {
        request.setAttribute("title", title);
    }
    
}
