package com.shzg.project.worn.websocket.endpoint;

import com.shzg.framework.security.LoginUser;
import com.shzg.framework.security.service.TokenService;
import com.shzg.project.system.domain.SysDept;
import com.shzg.project.system.mapper.SysDeptMapper;
import com.shzg.project.worn.websocket.domain.WsUserInfo;
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@Component
@ServerEndpoint("/ws")
public class WornWebSocketServer {

    private static WebSocketSessionManager sessionManager;
    private static SysDeptMapper deptMapper;
    private static TokenService tokenService;

    @Autowired
    public void setSessionManager(WebSocketSessionManager manager) {
        WornWebSocketServer.sessionManager = manager;
    }

    @Autowired
    public void setDeptMapper(SysDeptMapper mapper) {
        WornWebSocketServer.deptMapper = mapper;
    }

    @Autowired
    public void setTokenService(TokenService service) {
        WornWebSocketServer.tokenService = service;
    }

    @OnOpen
    public void onOpen(Session session) {
        log.info("[WebSocket] 连接建立 sessionId={}", session.getId());

        String query = session.getQueryString();
        if (query == null || !query.contains("token=")) {
            closeSession(session, "missing token");
            return;
        }

        try {
            // ===== 1. 解析token =====
            String token = parseToken(query);
            if (token == null || token.trim().isEmpty()) {
                closeSession(session, "invalid token");
                return;
            }

            // ===== 2. 获取登录用户 =====
            LoginUser loginUser = tokenService.getLoginUserByToken(token);
            if (loginUser == null) {
                closeSession(session, "invalid token");
                return;
            }

            Long userId = loginUser.getUserId();
            Long deptId = loginUser.getDeptId();
            String userName = loginUser.getUsername();

            boolean isAdmin = false;
            if (loginUser.getUser() != null) {
                isAdmin = loginUser.getUser().isAdmin();
            }

            if (deptId == null) {
                closeSession(session, "deptId is null");
                return;
            }

            // ===== 3. 计算部门范围（🔥重点修改）=====
            Set<Long> deptIds = new HashSet<>();

            if (isAdmin) {
                // 🔥 管理员：全部部门
                SysDept queryDept = new SysDept();
                List<SysDept> allDept = deptMapper.selectDeptList(queryDept);
                if (allDept != null && !allDept.isEmpty()) {
                    for (SysDept d : allDept) {
                        if (d != null && d.getDeptId() != null) {
                            deptIds.add(d.getDeptId());
                        }
                    }
                }
            } else {
                // 普通用户：当前部门 + 子部门
                List<SysDept> deptList = deptMapper.selectDeptAndChildren(deptId, null);

                if (deptList != null && !deptList.isEmpty()) {
                    for (SysDept dept : deptList) {
                        if (dept != null && dept.getDeptId() != null) {
                            deptIds.add(dept.getDeptId());
                        }
                    }
                } else {
                    deptIds.add(deptId);
                }
            }

            // ===== 4. 构造用户信息 =====
            WsUserInfo userInfo = new WsUserInfo();
            userInfo.setUserId(userId);
            userInfo.setUserName(userName);
            userInfo.setAdmin(isAdmin);
            userInfo.setDeptIds(deptIds);

            // ===== 5. 获取IP =====
            String ip = getIp(session);
            session.getUserProperties().put("ip", ip);

            // ===== 6. 注册连接 =====
            boolean success = sessionManager.register(session, userInfo);
            if (!success) {
                log.warn("[WebSocket] 连接被拒绝（限流）sessionId={}, ip={}", session.getId(), ip);
                closeSession(session, "too many connections");
                return;
            }

            log.info("[WebSocket] 注册成功 sessionId={}, userId={}, userName={}, ip={}, deptIds={}",
                    session.getId(), userId, userName, ip, deptIds);

        } catch (Exception e) {
            log.error("[WebSocket] 连接异常 sessionId={}", session.getId(), e);
            closeSession(session, "error");
        }
    }

    @OnClose
    public void onClose(Session session) {
        sessionManager.remove(session);
        log.info("[WebSocket] 连接关闭 sessionId={}", session.getId());
    }

    @OnError
    public void onError(Session session, Throwable error) {
        if (session != null) {
            sessionManager.remove(session);
            log.error("[WebSocket] 异常 sessionId={}", session.getId(), error);
        } else {
            log.error("[WebSocket] 异常", error);
        }
    }

    private String parseToken(String query) throws Exception {
        String[] params = query.split("&");
        for (String param : params) {
            if (param.startsWith("token=")) {
                String token = param.substring(6);
                token = URLDecoder.decode(token, "UTF-8");

                if (token.startsWith("Bearer ")) {
                    token = token.substring(7);
                }
                return token;
            }
        }
        throw new IllegalArgumentException("token not found");
    }

    private String getIp(Session session) {
        try {
            Object addr = session.getUserProperties().get("javax.websocket.endpoint.remoteAddress");
            if (addr instanceof InetSocketAddress) {
                InetSocketAddress inetSocketAddress = (InetSocketAddress) addr;
                if (inetSocketAddress.getAddress() != null) {
                    return inetSocketAddress.getAddress().getHostAddress();
                }
            }
        } catch (Exception e) {
            log.warn("[WebSocket] 获取客户端IP失败 sessionId={}", session.getId(), e);
        }
        return "unknown";
    }

    private void closeSession(Session session, String reason) {
        try {
            if (session != null && session.isOpen()) {
                session.close(new CloseReason(
                        CloseReason.CloseCodes.CANNOT_ACCEPT,
                        reason
                ));
            }
        } catch (IOException e) {
            log.error("[WebSocket] 关闭连接失败 sessionId={}", session != null ? session.getId() : "null", e);
        }
    }
}
