package com.bizzan.bitrade.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.constant.AnnouncementClassification;
import com.bizzan.bitrade.constant.SysConstant;
import com.bizzan.bitrade.controller.BaseController;
import com.bizzan.bitrade.entity.Announcement;
import com.bizzan.bitrade.entity.QAnnouncement;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.pagination.PageResult;
import com.bizzan.bitrade.service.AnnouncementService;
import com.bizzan.bitrade.service.MemberAnnouncementReadService;
import com.bizzan.bitrade.util.MessageResult;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;

import io.swagger.annotations.Api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;


/**
 * @author QQ 2232965526
 * @description
 * @date 2019/3/5 15:25
 */
@Api(value = "AnnouncementController", tags = "公告接口")
@RestController
@RequestMapping("announcement")
public class AnnouncementController extends BaseController {
    @Autowired
    private AnnouncementService announcementService;

    @Autowired
    private MemberAnnouncementReadService memberAnnouncementReadService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 从 JSON 字符串中按语言提取值，找不到则回退到 zh_CN
     */
    private String extractByLang(String jsonStr, String lang) {
        if (jsonStr == null || jsonStr.isEmpty()) return "";
        try {
            JSONObject json = JSON.parseObject(jsonStr);
            String value = json.getString(lang);
            if (value != null && !value.isEmpty()) return value;
            value = json.getString("zh_CN");
            return value != null ? value : "";
        } catch (Exception e) {
            return jsonStr;
        }
    }

    /**
     * 将公告的 title/content 替换为指定语言的文本（list 场景不返回 content）
     */
    private void applyLangForList(Announcement a, String lang) {
        a.setTitle(extractByLang(a.getTitle(), lang));
        a.setContent(null);
    }

    /**
     * 将公告的 title/content 替换为指定语言的文本（detail 场景）
     */
    private void applyLangForDetail(Announcement a, String lang) {
        a.setTitle(extractByLang(a.getTitle(), lang));
        a.setContent(extractByLang(a.getContent(), lang));
    }

    @PostMapping("page")
    public MessageResult page(
            @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
            @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
            @RequestHeader(value = "lang") String lang
    ) {
        ArrayList<Predicate> predicates = new ArrayList<>();
        predicates.add(QAnnouncement.announcement.isShow.eq(true));
        predicates.add(QAnnouncement.announcement.publishTime.loe(new Date())
                .or(QAnnouncement.announcement.publishTime.isNull()));
        ArrayList<OrderSpecifier> orderSpecifiers = new ArrayList<>();
        orderSpecifiers.add(QAnnouncement.announcement.createTime.desc());
        PageResult<Announcement> pageResult = announcementService.queryDsl(pageNo, pageSize, predicates, QAnnouncement.announcement, orderSpecifiers);
        List<Announcement> rlist = pageResult.getContent();
        for (Announcement a : rlist) {
            applyLangForList(a, lang);
        }
        pageResult.setContent(rlist);
        return success(pageResult);
    }

    @GetMapping("{id}")
    public MessageResult detail(
            @PathVariable("id") Long id,
            @RequestHeader(value = "lang", defaultValue = "zh_CN") String lang) {
        Announcement announcement = announcementService.findById(id);
        Assert.notNull(announcement, "validate id!");
        applyLangForDetail(announcement, lang);
        return success(announcement);
    }

    @GetMapping("contract")
    public MessageResult contractDetail(
            @RequestHeader(value = "lang") String lang) {
        Announcement announcement = announcementService.findByContract();
        if (announcement != null) applyLangForDetail(announcement, lang);
        return success(announcement);
    }

    @GetMapping("system")
    public MessageResult systemDetail(
            @RequestHeader(value = "lang") String lang) {
        Announcement announcement = announcementService.findByClassification(AnnouncementClassification.SYSTEM);
        if (announcement != null) applyLangForDetail(announcement, lang);
        return success(announcement);
    }

    @RequestMapping(value = "more", method = RequestMethod.POST)
    public MessageResult moreDetail(
            @RequestParam("id") Long id,
            @RequestHeader(value = "lang") String lang) {
        ValueOperations redisOperations = redisTemplate.opsForValue();
        String cacheKey = SysConstant.NOTICE_DETAIL + id + ":" + lang;
        JSONObject result = (JSONObject) redisOperations.get(cacheKey);
        if (result != null) {
            return success(result);
        }
        Announcement announcement = announcementService.findById(id);
        Assert.notNull(announcement, "validate id!");
        applyLangForDetail(announcement, lang);

        Announcement back = announcementService.getBack(id);
        if (back != null) applyLangForList(back, lang);

        Announcement next = announcementService.getNext(id);
        if (next != null) applyLangForList(next, lang);

        JSONObject resultObj = new JSONObject();
        resultObj.put("info", announcement);
        resultObj.put("back", back);
        resultObj.put("next", next);
        redisOperations.set(cacheKey, resultObj, SysConstant.NOTICE_DETAIL_EXPIRE_TIME, TimeUnit.SECONDS);
        return success(resultObj);
    }

    @GetMapping("popups")
    public MessageResult popups(@RequestHeader(value = "lang") String lang) {
        ArrayList<Predicate> predicates = new ArrayList<>();
        predicates.add(QAnnouncement.announcement.isShow.eq(true));
        predicates.add(QAnnouncement.announcement.isPopup.eq(true));
        predicates.add(QAnnouncement.announcement.publishTime.loe(new Date())
                .or(QAnnouncement.announcement.publishTime.isNull()));
        ArrayList<OrderSpecifier> orderSpecifiers = new ArrayList<>();
        orderSpecifiers.add(QAnnouncement.announcement.publishTime.desc());
        orderSpecifiers.add(QAnnouncement.announcement.id.desc());
        PageResult<Announcement> pageResult = announcementService.queryDsl(
                1, 20, predicates, QAnnouncement.announcement, orderSpecifiers);
        List<Announcement> list = pageResult.getContent();
        for (Announcement a : list) {
            applyLangForDetail(a, lang);
        }
        return success(list);
    }

    @GetMapping("unread-count")
    public MessageResult unreadCount(
            @SessionAttribute(SESSION_MEMBER) AuthMember user,
            @RequestHeader(value = "lang") String lang) {
        long unread = memberAnnouncementReadService.countUnread(user.getId());
        Announcement latest = memberAnnouncementReadService.findLatest();
        if (latest != null) applyLangForList(latest, lang);
        List<Long> readIds = memberAnnouncementReadService.getReadIds(user.getId());
        Map<String, Object> data = new HashMap<>();
        data.put("unreadCount", unread);
        data.put("hasUnread", unread > 0);
        data.put("latestId", latest != null ? latest.getId() : null);
        data.put("readIds", readIds);
        return success(data);
    }

    @PostMapping("mark-read")
    public MessageResult markRead(
            @SessionAttribute(SESSION_MEMBER) AuthMember user,
            @RequestParam("id") Long id) {
        memberAnnouncementReadService.markRead(user.getId(), id);
        return success();
    }
}
