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

import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.entity.Cate;
import me.qwq.doghouse.entity.Tag;
import me.qwq.doghouse.entity.config.WikiConfig;
import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.enums.PostStatusEnum;
import me.qwq.doghouse.exception.RException;
import me.qwq.doghouse.pojo.dto.LayPageReq;
import me.qwq.doghouse.pojo.dto.LayPageResp;
import me.qwq.doghouse.pojo.dto.R;
import me.qwq.doghouse.service.post.WikiService;
import me.qwq.doghouse.util.EscapeUnescapeUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;

import jakarta.servlet.http.Cookie;


/**
 * Post 后台控制器
 * @author Doghole
 */
@Controller
@RequestMapping("/admin/v2/wiki")
@Slf4j
public class AdminWikiController extends AbstractAdminPostController<WikiConfig, WikiService> {

    @Autowired
    WikiService wikiService;
    
    /**
     * 重写 Wiki 列表渲染
     */
    @Override
    public LayPageResp<?> getPostList(
            LayPageReq<Post> pageReq, 
            Post condition, 
            Long categoryId, 
            Long tagId,
            String keywords) {
        
        if (condition != null) {
            List<Long> unfolded = WikiService.getUnfoldedWikis(request);
            if (unfolded == null) {
                Cookie unfoldedCookie = new Cookie(WikiService.UNFOLDED_WIKIS, 
                        EscapeUnescapeUtils.escape("[]"));
                unfoldedCookie.setPath("/");
                response.addCookie(unfoldedCookie);
            }
            
            MPJLambdaWrapper<Post> ew = wikiService.getWikiDefaultWrapper(true)
                    // TODO
                    //.likeOrEqNotNull(condition)
                    .eq(Objects.nonNull(condition.getParentId()), Post::getParentId, condition.getParentId())
                    .eq(Objects.nonNull(condition.getType()), Post::getType, condition.getType())
                    .eq(Post::getIsDeleted, false)
                    .eq(Objects.nonNull(categoryId), Cate::getMid, categoryId)
                    .eq(Objects.nonNull(tagId), Tag::getMid, tagId)
                    .and(StringUtils.isNotBlank(keywords), o -> {
                        o.like(Post::getPostTitle, keywords)
                         .or().like(Post::getPostPreface, keywords)
                         .or().like(Post::getPostContent, keywords)
                         .or().like(Post::getKeywords, keywords);
                    });
            if (condition.getParentId() == null) {
                // 分页模型
                IPage<Post> page = wikiService.pageWikiWithChildren(pageReq, ew, unfolded);
                LayPageResp<Post> result = new LayPageResp<>(page);
                return result;
            }
            else {
                // 单独查询
                List<Post> listPost = wikiService.listWikiWithChildren(ew, unfolded);
                return new LayPageResp<Post>().setData(listPost).setCount(listPost.size());
            }
        }
        else {
            return super.getPostList(pageReq, condition, categoryId, tagId, keywords);
        }
    }
    
    @Override
    public R<?> batchOp(
            @RequestParam(value="ids[]", required=true)
            Long[] ids, PostStatusEnum postStatus) {

        if (Objects.isNull(ids) || ids.length == 0) {
            throw RException.badRequest("提供的批量操作 ID 不能为空");
        }
        
        // 接口方法未实现 to 参数接收, 这里手动从 request 里面取
        Long to = null;
        
        try {
            String toString = request.getParameter("to");
            if (!StringUtils.isBlank(toString)) {
                to = Long.valueOf(toString);
            }
        }
        catch (NumberFormatException e) {
            throw RException.badRequest("错误的移动层级");
        }
        
        List<Long> idArray = Arrays.asList(ids);
        
        LambdaUpdateWrapper<Post> uw =
                new LambdaUpdateWrapper<Post>()
                .in(Post::getPostId, idArray);
        
        boolean delete = Objects.isNull(postStatus) && Objects.isNull(to); // 删除
        boolean changeStatus = !delete && Objects.nonNull(postStatus);     // 更新状态
        boolean move = !delete && !changeStatus && to != null;             // 移动层级
        
        if (!(delete || changeStatus || move)) {
            throw RException.badRequest("非法操作"); 
        }
        
        if (!move) {
            uw.set(delete, Post::getIsDeleted, true);
            uw.set(changeStatus, Post::getPostStatus, postStatus);
            uw.set(changeStatus && postStatus != PostStatusEnum.RELEASED, Post::getSearchable, false);
            if (wikiService.update(uw)) {
                // 更新可能包含的子级
                boolean subOperationFlag = true;
                for (Long id : idArray) {
                    Post post = wikiService.getById(id);
                    if (delete ?
                            wikiService.deleteChildren(post) : 
                            wikiService.resetSearchableStatus(post)) {
                        continue;
                    }
                    else {
                        subOperationFlag = false;
                        log.warn(delete ? 
                                "删除 postId={}, title={} 子项失败":
                                "重设 postId={}, title={} Wiki 子项可搜索状态失败",
                                id, post.getTitle());
                    }
                }
                // TODO 这里应该做成事务
                return R.judge(subOperationFlag, 
                        delete ? 
                            "删除部分子项失败, 请查看输出日志" : 
                            "重设部分子项可搜索状态失败，请查看输出日志");
            }
            else {
                throw RException.internalServerError("批量操作保存失败");
            }
        }
        
        // to
        if (to < -1L) {
            // 移动到顶级
            to = -1L;
        }
        else if (to >= 0) {

            // 检查父子从属关系
            List<Post> childToParent = wikiService.listFromChildToParent(to, true, true);
            if (childToParent.isEmpty()) {
                throw RException.badRequest("指定移动至的目标 Wiki 不存在");
            }
            // 如果传过来的 ids 中有 id 处在父子从属列表中
            // 则表明是想将父类移动到子类，或者想将自己移动到自己
            if (childToParent.stream().mapToLong(Post::getPostId).anyMatch(id -> idArray.contains(id))) {
                throw RException.badRequest("不允许将父级或本级移动到子级或本级");
            }
        }
        
        // 获取欲移动的 Post 的原 parentId，待移动成功后重排这些 parent 下的子级
        List<Long> originalParentIds = getPostService().getParentIds(idArray);
        
        try {
            if (!getPostService().batchMoveTo(idArray, to)) {
                throw RException.badRequest("重设排序失败");
            }
            
            for (Long parentId : originalParentIds) {
                if (!wikiService.reorderChildren(parentId)) {
                    log.warn(
                      "重排原 parentId = {} 下子级失败，但移动将继续", parentId);
                }
            }
            
            
            // 移动后重设可搜索状态
            if (to != -1L) {
                Post toPost = getPostService().getById(to);
                if (!wikiService.resetSearchableStatus(toPost)) {
                    log.warn("重设 postId={}, title={} Wiki 子项可搜索状态失败", to, toPost.getTitle());
                    throw RException.internalServerError("重设部分子项可搜索状态失败，请查看输出日志");
                }
            }
            else {
                // 判断原本是否有密码
                uw.set(Post::getSearchable, true)
                  .eq(Post::getPassword, "");
                if (!getPostService().update(uw)) {
                    throw RException.internalServerError("重设移动到顶级的可搜索状态失败");
                }
                boolean resetSearchableOk = true;
                for (Long id : idArray) {
                    Post post = getPostService().getById(id);
                    if (wikiService.resetSearchableStatus(post)) {
                        continue;
                    }
                    else {
                        resetSearchableOk = false;
                        log.warn("重设 postId={}, title={} Wiki 子项可搜索状态失败", id, post.getTitle());
                    }
                }
                if (resetSearchableOk)
                    return R.ok();
                else {
                    throw RException.internalServerError("重设部分子项可搜索状态失败，请查看输出日志");
                }
            }
            return R.ok();
        }
        catch (Exception e) {
            if (e instanceof RException) {
                throw e;
            }
            log.error("批量移动层级失败", e);
        }
        throw RException.internalServerError("批量操作失败");
    }
    
    /**
     * 重排, 只有 Wiki 有这个操作
     * <p>TODO 前端使用拖拽来实现重排
     * @param postId
     * @param up
     * @return
     */
    @ResponseBody
    @PostMapping("/reorder")
    public R<?> reorder(@RequestParam Long postId, boolean up) {
        try {
            if (!getPostService().reorder(postId, up)) {
                throw RException.badRequest("重设排序失败");
            }
        } catch (RException e) {
            throw e;
        }
        return R.ok(postId);
    }
    
}
