package com.xjrsoft.module.oa.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.DeleteMark;
import com.xjrsoft.common.model.result.RT;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.oa.dto.*;
import com.xjrsoft.module.oa.entity.News;
import com.xjrsoft.module.oa.entity.NewsRelation;
import com.xjrsoft.module.oa.entity.NewsRelationConfig;
import com.xjrsoft.module.oa.service.INewsRelationConfigService;
import com.xjrsoft.module.oa.service.INewsRelationService;
import com.xjrsoft.module.oa.service.INewsService;
import com.xjrsoft.module.oa.vo.*;
import com.xjrsoft.module.teacher.entity.XjrUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 公告
 * @author zlf
 * @since 2022-06-16
 */
@RestController
@RequestMapping(GlobalConstant.OA_MODULE_PREFIX + "/proclamation")
@Api(value = GlobalConstant.OA_MODULE_PREFIX + "/proclamation", tags = "公告")
@AllArgsConstructor
public class ProclamationController {

    private INewsService newsService;
    private INewsRelationService newsRelationService;
    private INewsRelationConfigService newsRelationConfigService;
    
    @GetMapping(value = "/gradeClassTree")
    @ApiOperation(value="公告年级班级树")
    public RT<List<NewsGradeClassTreeVo>> gradeClassTree(){
        List<NewsGradeClassTreeVo> list = newsService.getGradeClassTree();
        if(ObjectUtil.isNull(list) || list.size() == 0){
            return RT.error("找不到此数据！");
        }
        return RT.ok(list);
    }

    @GetMapping("/manage-box")
    @ApiOperation(value = "获取管理公告分页")
    public RT<PageOutput<ProclamationPageVo>> manageBox(ProclamationPageDto dto) {
        IPage<ProclamationPageVo> page = newsService.proclamationManageBox(dto);
        PageOutput<ProclamationPageVo> pageOutput = ConventPage.getPageOutput(page, ProclamationPageVo.class);
        return RT.ok(pageOutput);
    }

    @GetMapping("/receipt-box")
    @ApiOperation(value = "获取接受公告分页")
    public RT<PageOutput<ProclamationPageVo>> receiptBox(ProclamationPageDto dto) {
        IPage<ProclamationPageVo> page = newsService.proclamationReceiptBox(dto);
        PageOutput<ProclamationPageVo> pageOutput = ConventPage.getPageOutput(page, ProclamationPageVo.class);
        return RT.ok(pageOutput);
    }


    @PostMapping
    @ApiOperation(value = "新增公告")
    public RT<Boolean> add(@RequestBody AddProclamationDto addProclamationDto) {
        Long newsId = newsService.addProclamation(addProclamationDto);
        if(newsId != -1L){
            CompletableFuture.runAsync(() -> {
                newsService.SendMessage(newsId);
            });
        }
        return RT.ok(true);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "公告详情")
    public RT<ProclamationVo> info(@RequestParam Long id) {
        ProclamationVo proclamationVo = newsService.getProclamationById(id);
        if (proclamationVo == null) {
            RT.error("找不到此公告！");
        }
        return RT.ok(proclamationVo);
    }

    @PutMapping
    @ApiOperation(value = "修改公告")
    public RT<Boolean> update(@RequestBody UpdateProclamationDto updateProclamationDto) {
        //News news = BeanUtil.toBean(updateNewsDto, News.class);
        return RT.ok(newsService.updateProclamation(updateProclamationDto));
    }

    @DeleteMapping
    @ApiOperation(value = "删除公告")
    public RT<Boolean> delete(@RequestBody List<Long> ids) {
        return RT.ok(newsService.delete(ids));
    }


    @PutMapping("/change-status")
    @ApiOperation(value = "发布或下架公告")
    public RT<Boolean> changeStatus(@RequestBody ChangeNewsDto changeNewsDto){
        if(newsService.changeStatus(changeNewsDto)){
            CompletableFuture.runAsync(() -> {
                newsService.SendMessage(changeNewsDto.getId());
            });
        }
        return RT.ok(true);
    }

    @PutMapping("/read")
    @ApiOperation(value = "读公告")
    public RT<Boolean> read(@RequestBody List<Long> ids) {
        List<NewsRelation> toSaveList = newsRelationService.list(
                Wrappers.<NewsRelation>query().lambda()
                        .in(NewsRelation::getNewsId, ids)
                        .eq(NewsRelation::getUserId, StpUtil.getLoginIdAsLong()));
        for (NewsRelation newsRelation : toSaveList) {
            newsRelation.setReadMark(1);
            newsRelation.setReadDate(LocalDateTime.now());
        }
//        newsRelationService.remove(Wrappers.<NewsRelation>query().lambda()
//                .in(NewsRelation::getNewsId, ids)
//                .eq(NewsRelation::getUserId, StpUtil.getLoginIdAsLong()));
        return RT.ok(newsRelationService.updateBatchById(toSaveList));
    }

    @PutMapping("/reply")
    @ApiOperation(value = "公告回复")
    public RT<Boolean> reply(@RequestBody NewsReplyDto newsReplyDto) {
        NewsRelation newsRelation = newsRelationService.getOne(
                Wrappers.<NewsRelation>query().lambda()
                        .eq(NewsRelation::getNewsId, newsReplyDto.getId())
                        .eq(NewsRelation::getUserId, StpUtil.getLoginIdAsLong()));
        if (newsRelation == null) {
            newsRelation = new NewsRelation();
            newsRelation.setNewsId(newsReplyDto.getId());
            newsRelation.setUserId(StpUtil.getLoginIdAsLong());
            newsRelation.setReadMark(1);
            newsRelation.setReadDate(LocalDateTime.now());
            newsRelation.setReplyContent(newsReplyDto.getReplyContent());
            return RT.ok(newsRelationService.save(newsRelation));
        }

        if (newsRelation.getReadMark() == null || newsRelation.getReadMark() == 0) {
            newsRelation.setReadMark(1);
            newsRelation.setReadDate(LocalDateTime.now());
        }
        newsRelation.setReplyContent(newsReplyDto.getReplyContent());
        return RT.ok(newsRelationService.updateById(newsRelation));
    }

    @GetMapping("/page-relation")
    @ApiOperation(value = "获取公告阅读权限分页")
    public RT<PageOutput<NewsRelationVo>> pageRelation(NewsRelationPageDto dto) {

        IPage<NewsRelationVo> page = newsRelationService.selectJoinListPage(ConventPage.getPage(dto), NewsRelationVo.class,
                new MPJLambdaWrapper<NewsRelation>()
                        .eq(NewsRelation::getNewsId, dto.getNewsId())
                        .eq(ObjectUtil.isNotEmpty(dto.getReadMark()) && dto.getReadMark() > 0, NewsRelation::getReadMark, dto.getReadMark() == 1 ? 0 : 1)
                        .isNull(ObjectUtil.isNotEmpty(dto.getReplyMark()) && dto.getReplyMark() == 1, NewsRelation::getReplyContent)
                        .isNotNull(ObjectUtil.isNotEmpty(dto.getReplyMark()) && dto.getReplyMark() == 2, NewsRelation::getReplyContent)
                        .select(NewsRelation::getId)
                        .select(NewsRelation.class, x -> VoToColumnUtil.fieldsToColumns(NewsRelationVo.class).contains(x.getProperty()))
                        .leftJoin(XjrUser.class, XjrUser::getId, NewsRelation::getUserId, ext -> ext.selectAs(XjrUser::getName, NewsRelationVo::getUserName))
        );
        PageOutput<NewsRelationVo> pageOutput = ConventPage.getPageOutput(page);
        return RT.ok(pageOutput);
    }


    @GetMapping("/page-relation-config")
    @ApiOperation(value = "获取公告权限分页")
    public RT<PageOutput<NewsRelationConfigVo>> pageRelationConfig(NewsRelationPageDto dto) {
        Wrapper<NewsRelationConfig> wrapper = Wrappers.<NewsRelationConfig>query().lambda()
                .eq(NewsRelationConfig::getNewsId, dto.getNewsId())
                .select(NewsRelationConfig.class, x -> VoToColumnUtil.fieldsToColumns(NewsRelationConfigVo.class).contains(x.getProperty()));

        IPage<NewsRelationConfig> page = newsRelationConfigService.page(ConventPage.getPage(dto), wrapper);
        PageOutput<NewsRelationConfigVo> pageOutput = ConventPage.getPageOutput(page, NewsRelationConfigVo.class);
        return RT.ok(pageOutput);
    }

    @PutMapping("/update-relation")
    @ApiOperation(value = "设置公告阅读权限")
    public RT<Boolean> updateRelation(@RequestBody UpdateNewsRelationDto updateRelationDto) {
        return RT.ok(newsService.updateRelation(updateRelationDto));
    }

    @DeleteMapping("/delete-relation")
    @ApiOperation(value = "删除公告阅读权限")
    public RT<Boolean> deleteRelation(@RequestBody DeleteNewsRelationDto deleteNewsRelationDto) {
        return RT.ok(newsService.deleteRelation(deleteNewsRelationDto));
    }

    @GetMapping("/count-relation")
    @ApiOperation(value = "公告阅读权限统计")
    public RT<Long[]> countRelation(@RequestParam Long id) {
        Long total = newsRelationService.count(Wrappers.<NewsRelation>query().lambda().eq(NewsRelation::getNewsId, id));
        Long notRead = newsRelationService.count(Wrappers.<NewsRelation>query().lambda().eq(NewsRelation::getNewsId, id).eq(NewsRelation::getReadMark, 0));
        Long isRead = newsRelationService.count(Wrappers.<NewsRelation>query().lambda().eq(NewsRelation::getNewsId, id).eq(NewsRelation::getReadMark, 1));
        Long isReply = newsRelationService.count(Wrappers.<NewsRelation>query().lambda().eq(NewsRelation::getNewsId, id).isNotNull(NewsRelation::getReplyContent));
        Long notReply = newsRelationService.count(Wrappers.<NewsRelation>query().lambda().eq(NewsRelation::getNewsId, id).isNull(NewsRelation::getReplyContent));
        Long[] arrayRefVar = {total, notRead, isRead, isReply, notReply};
        return RT.ok(arrayRefVar);
    }

    @GetMapping("/count-type")
    @ApiOperation(value = "未读类型统计")
    public RT<List<NewsCountTypeVo>> countType() {
        List<NewsCountTypeVo> newsCountTypeVoList = new ArrayList<>();
        Integer typeIds[] = {1, 2, 3};
        for (Integer typeId : typeIds) {
            Long totalType = newsRelationService.count(Wrappers.<NewsRelation>query().lambda().eq(NewsRelation::getUserId, StpUtil.getLoginIdAsLong()).eq(NewsRelation::getReadMark, 0).in(NewsRelation::getNewsId, "SELECT id from xjr_oa_news where delete_mark = 0 and type_id=" + typeId));
            NewsCountTypeVo newsCountTypeVo = new NewsCountTypeVo();
            newsCountTypeVo.setTypeId(typeId);
            newsCountTypeVo.setTotal(totalType);
            News news = new News();
            if(typeId == 1){
                news = newsService.getOne(Wrappers.<News>query().lambda().eq(News::getTypeId, typeId).orderByDesc(News::getReleaseTime).last("limit 1"));
            }
            if(typeId == 2){
                //找到和该登录用户有关系的最后一条公告
                News newsRelation = newsService.selectJoinOne(News.class,
                        new MPJLambdaWrapper<News>()
                                .disableSubLogicDel()
                                .eq(News::getTypeId, typeId)
                                .eq(NewsRelation::getUserId, StpUtil.getLoginIdAsLong())
                                .orderByDesc(News::getReleaseTime)
                                .last("limit 1")
                                .innerJoin(NewsRelation.class, NewsRelation::getNewsId, News::getId));

                news = newsRelation;
                //找到晚于和该登录用户有关系的所有公告
                List<News> newsList = newsService.list(Wrappers.<News>query().lambda().eq(News::getTypeId, typeId).lt(News::getReleaseTime, newsRelation.getReleaseTime()).orderByDesc(News::getReleaseTime));
                for (News n : newsList) {
                    if(n.getSendRange() == 1){//是发给所有人的
                        news = n;
                        break;
                    }
                }
            }
            if (news != null) {
                newsCountTypeVo.setTime(news.getReleaseTime());
                newsCountTypeVo.setTitle(news.getBriefHead());
            }
            newsCountTypeVoList.add(newsCountTypeVo);
        }
        return RT.ok(newsCountTypeVoList);
    }

    @GetMapping("/send-message")
    @ApiOperation(value = "发送消息")
    public RT<Boolean> sendMessage(@RequestParam Long id) {
        return RT.ok(newsService.SendMessage(id));
    }

    @GetMapping("/unread-count")
    @ApiOperation(value = "获取登录人未读消息数量")
    public RT<Integer> unreadCount() {
        Integer count = newsService.selectJoinCount(
            new MPJLambdaWrapper<News>()
            .eq(NewsRelation::getReadMark, 0)
            .eq(NewsRelation::getUserId, StpUtil.getLoginIdAsLong())
            .eq(News::getDeleteMark, DeleteMark.NODELETE.getCode())
            .innerJoin(NewsRelation.class, NewsRelation::getNewsId, News::getId)
        );
        return RT.ok(count);
    }
}
