package com.fs.app.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fs.common.utils.PubFun;
import com.fs.company.domain.CompanyWxAccount;
import com.fs.company.service.ICompanyWxAccountService;
import com.fs.wxcid.domain.CidIpadServer;
import com.fs.wxcid.dto.callback.WxCallbackVo;
import com.fs.wxcid.service.ICidIpadServerService;
import com.fs.wxcid.service.IWxMsgLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


@Slf4j
@Component
public class WebscoketServer {
    @Autowired
    private ICidIpadServerService cidIpadServerService;
    @Autowired
    private ICompanyWxAccountService companyWxAccountService;
    @Autowired
    private IWxMsgLogService wxMsgLogService;
    @Value("${group-no}")
    private String groupNo;

    // 重连间隔（秒）
    private static final int RECONNECT_INTERVAL = 5;
    // 客户端会话
    private Map<Long, Session> sessionMap = new ConcurrentHashMap<>();
    // ipad 数据
    private Map<Long, CidIpadServer> ipadMap = new HashMap<>();
    // 重连调度器
    private final ScheduledExecutorService reconnectScheduler = Executors.newSingleThreadScheduledExecutor();

    /**
     * 启动客户端（连接第三方 + 监听消息）
     */
    public void start() {
        List<CidIpadServer> ipadList = cidIpadServerService.list(new QueryWrapper<CidIpadServer>().eq("group_no", groupNo));
        if(ipadList.isEmpty()){
            log.info("没有需要连接的账号");
            return;
        }
        ipadMap = PubFun.listToMapByGroupObject(ipadList, CidIpadServer::getId);
        List<CompanyWxAccount> list = companyWxAccountService.list(new QueryWrapper<CompanyWxAccount>().eq("server_status", 1).eq("login_status", 1).in("server_id", PubFun.listToNewList(ipadList, CidIpadServer::getId)));
        list.forEach(this::connect);
//        connect();
    }

    /**
     * 连接第三方 WebSocket 服务
     */
    private void connect(CompanyWxAccount account) {
        try {
            CidIpadServer ipad = ipadMap.get(account.getServerId());
            String url = "ws://" + ipad.getIp() + ":" + ipad.getPort() + "/ws/GetSyncMsg?key=" + account.getAuthKey();
            // 1. 创建 WebSocket 客户端容器（SpringBoot 2 内置）
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            // 2. 连接第三方服务，绑定消息处理器
            container.connectToServer(new WebSocketMessageHandler(account, ipad), URI.create(url));
            log.info("✅ 原生 WebSocket 连接第三方服务成功：{}", url);
        } catch (Exception e) {
            log.error("❌ 原生 WebSocket 连接失败：{}", e.getMessage(), e);
            scheduleReconnect(account);
        }
    }

    /**
     * 消息处理器（核心：接收/处理第三方消息）
     */
    @ClientEndpoint
    public class WebSocketMessageHandler {
        private CompanyWxAccount account;
        private CidIpadServer ipad;
        public WebSocketMessageHandler(CompanyWxAccount account, CidIpadServer ipad) {
            this.account = account;
            this.ipad = ipad;
        }

        // 连接成功回调（保存会话）
        @OnOpen
        public void onOpen(Session session) {
            sessionMap.put(account.getId(), session);
            log.info("✅ WebSocket 会话建立，SessionID：{}", session.getId());
            // 取消重连（若有）
            reconnectScheduler.shutdownNow();
        }

        // 接收第三方消息（核心业务逻辑）
        @OnMessage
        public void onMessage(String message) {
            WxCallbackVo callbackVo = JSON.parseObject(message, WxCallbackVo.class);
            log.info("📩 收到第三方 WebSocket 消息：{}", callbackVo);
            WxCallbackVo.Message msgVo = callbackVo.getMessage();
            String formUser = msgVo.getFromUserName().getStr();
            if(msgVo.getMsgType() == 10000 && "以上是打招呼的消息".equals(msgVo.getContent().getStr())){
                companyWxAccountService.isCheckContact(formUser, account.getId());
            }
            wxMsgLogService.insertLog(callbackVo, account, !formUser.equals(account.getWxNo()) ? 0 : 1);
        }

        // 处理二进制消息（若第三方推送二进制数据，如文件/字节流）
        @OnMessage
        public void onMessage(byte[] binaryData) {
            log.info("📩 收到第三方二进制消息，长度：{} 字节", binaryData.length);
        }

        // 连接关闭回调（触发重连）
        @OnClose
        public void onClose(Session session, CloseReason reason) {
            log.error("❌ WebSocket 会话关闭：{}，{}秒后重连", reason.getReasonPhrase(), RECONNECT_INTERVAL);
            sessionMap.remove(account.getId());
            scheduleReconnect(account);
        }

        // 连接异常回调（触发重连）
        @OnError
        public void onError(Session session, Throwable error) {
            log.error("连接报错！！！", error);
        }
    }

    /**
     * 调度重连
     */
    private void scheduleReconnect(CompanyWxAccount account) {
        if (!reconnectScheduler.isShutdown()) {
            reconnectScheduler.schedule(() -> connect(account), RECONNECT_INTERVAL, TimeUnit.SECONDS);
            log.info("⏳ 已调度 {} 秒后重连第三方 WebSocket 服务", RECONNECT_INTERVAL);
        }
    }
}

