import { WebSocket, WebSocketServer } from 'ws'
import { z } from "zod"
import jwt from 'jsonwebtoken'
import ForumHandler from "./handlers/ForumHandler.js"
import MessagesHandler from "./handlers/MessagesHandler.js"

export default class Socket {
    wss;
    messageSchema = z.object({
        id: z.string(),
        app: z.string(),
        operation: z.string().optional(),
        msg: z.union([
            z.object({}).passthrough(), // allows any object
            z.array(z.any())            // allows any array
        ]).optional()
    })
    .superRefine((data, ctx) => {
        if (data.operation !== "GET" && data.msg === undefined) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                path: ["msg"],
                message: "msg is required when operation is not GET"
            })
        }
    })
    .strict()

    constructor(server) {
        this.wss = new WebSocketServer({ server });

        this.wss.on('connection', (ws, req) => {
            console.log('✅ New WebSocket client connected');

            function parseCookies(cookieHeader = "") {
                return Object.fromEntries(
                    cookieHeader.split(";").map(c => {
                        const [key, ...v] = c.trim().split("=");
                        return [key, decodeURIComponent(v.join("="))];
                    })
                );
            }

            const cookies = parseCookies(req.headers.cookie);
            const token = cookies.auth_token;
            if (!token) throw new Error("No auth token");
            const payload = jwt.verify(token, process.env.JWT_SECRET);
            ws.userEmail = payload.email;
            
            ws.on('message', (msg) => {
                this.handleMessage(msg, ws);
            });

            ws.on('close', () => {
                console.log('Client disconnected');
            });
        });

        console.log('WebSocket server initialized');
    }

    // Build a system where the ws obj is updated every time on navigate, so it already has context
    // this way, we can only send broadcast messages to clients that actually have that app / subapp open
    handleMessage = (msg, ws) => {
        console.log("websocket message received: ", msg)
    }

    broadcast(event) {
        if (!this.wss) return;

        let message = JSON.stringify(event)

        this.wss.clients.forEach(ws => {
            if (ws.readyState === WebSocket.OPEN) {
                ws.send(message);
            }
        });
    }
}
