package ink.wgink.module.wechat.controller.wechat.official.account;

import ink.wgink.common.base.DefaultBaseController;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.exceptions.PropertiesException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.wechat.enums.XmlEventTypeEnum;
import ink.wgink.module.wechat.enums.XmlMsgTypeEnum;
import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountUserVO;
import ink.wgink.module.wechat.result.OfficialAccountEventResult;
import ink.wgink.module.wechat.service.official.account.IOfficialAccountCheckService;
import ink.wgink.module.wechat.service.official.account.IOfficialAccountTextService;
import ink.wgink.module.wechat.service.official.account.IOfficialAccountUserService;
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
import ink.wgink.util.xml.XMLUtil;
import io.swagger.annotations.Api;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.concurrent.CompletableFuture;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: OfficialAccountWechatController
 * @Description: 微信公众号
 * @Author: wanggeng
 * @Date: 2021/4/28 3:15 下午
 * @Version: 1.0
 */
@Api(tags = ISystemConstant.API_TAGS_WECHAT_PREFIX + "微信公众号")
@RestController
@RequestMapping(ISystemConstant.WECHAT_PREFIX + "/official/account")
public class OfficialAccountWechatController extends DefaultBaseController {

    @Autowired
    private OfficialAccountProperties officialAccountProperties;
    @Autowired
    private IOfficialAccountCheckService officialAccountCheckService;
    @Autowired
    private IOfficialAccountUserService officialAccountUserService;
    @Autowired
    private IOfficialAccountTextService officialAccountTextService;

    @RequestMapping("event")
    public void event(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (!officialAccountProperties.getActivate()) {
            throw new PropertiesException("公众号配置未激活");
        }
        // 处理认证
        if (StringUtils.equalsIgnoreCase(HttpMethod.GET.toString(), request.getMethod())) {
            officialAccountCheckService.checkSignature(request, response);
            return;
        }
        // 处理事件
        if (StringUtils.equalsIgnoreCase(HttpMethod.POST.toString(), request.getMethod())) {
            AsyncContext asyncContext = request.startAsync();
            CompletableFuture.runAsync(() -> {
                try {
                    handleMsgType(asyncContext, request, response);
                } catch (IOException e) {
                    LOG.error(e.getMessage(), e);
                }
            });
            return;
        }
    }

    /**
     * 处理消息类型
     *
     * @param asyncContext
     * @param request
     * @param response
     */
    private void handleMsgType(AsyncContext asyncContext, HttpServletRequest request, HttpServletResponse response) throws IOException {
        OfficialAccountEventResult officialAccountEventResult = getEventResult(request);
        // 处理消息事件
        if (officialAccountEventResult == null) {
            throw new ParamsException("事件错误");
        }
        if (StringUtils.equalsIgnoreCase(XmlMsgTypeEnum.EVENT.getValue(), officialAccountEventResult.getMsgType())) {
            // 解析完流之后，直接返回，防止微信服务器重复请求
            PrintWriter writer = response.getWriter();
            writer.write("");
            writer.flush();
            asyncContext.complete();
            handleEvent(officialAccountEventResult, request, response);
        } else if (StringUtils.equalsIgnoreCase(XmlMsgTypeEnum.TEXT.getValue(), officialAccountEventResult.getMsgType())) {
            officialAccountTextService.getReplay(officialAccountEventResult, asyncContext, response);
        }
    }

    /**
     * 处理事件
     *
     * @param officialAccountEventResult
     * @param request
     * @param response
     */
    private void handleEvent(OfficialAccountEventResult officialAccountEventResult, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.equalsIgnoreCase(XmlEventTypeEnum.SUBSCRIBE.getType(), officialAccountEventResult.getEvent())) {
            OfficialAccountUserVO officialAccountUserVO = new OfficialAccountUserVO();
            officialAccountUserVO.setOpenId(officialAccountEventResult.getFromUserName());
            synchronized (this) {
                officialAccountUserService.save(officialAccountUserVO);
            }
        } else if (StringUtils.equalsIgnoreCase(XmlEventTypeEnum.UNSUBSCRIBE.getType(), officialAccountEventResult.getEvent())) {
            officialAccountUserService.updateStatus(officialAccountEventResult.getFromUserName(), XmlEventTypeEnum.UNSUBSCRIBE);
        }
    }

    /**
     * 事件结果
     *
     * @param request
     * @return
     */
    private OfficialAccountEventResult getEventResult(HttpServletRequest request) {
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
            StringBuilder content = new StringBuilder();
            for (String line; (line = bufferedReader.readLine()) != null; ) {
                content.append(line);
            }
            return XMLUtil.xml2SampleBean(content.toString(), OfficialAccountEventResult.class);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

}
