import { Server } from "socket.io";
import { Redis } from "ioredis";
import jwt from "jsonwebtoken";

const jwtSecret = process.env.JWT_SECRET;
const port = process.env.PORT || 3000;
const io = new Server(port, {
    cors: {
        origin: "*",
        credentials: true,
    },
});
const redis = new Redis({
    port: 6379,
    host: "redis",
    username: "default",
    password: process.env.REDIS_PASSWORD,
    db: 0,
});

io.engine.use((req, res, next) => {
    const isHandshake = req._query.sid === undefined;

    if (!isHandshake) {
        return next();
    }

    const header = req.headers["authorization"];

    if (!header) {
        return next(new Error("no token"));
    }

    if (!header.startsWith("Bearer ")) {
        return next(new Error("invalid token"));
    }

    const token = header.substring(7);

    jwt.verify(token, jwtSecret, (err, decoded) => {
        if (err) {
            return next(new Error("invalid token"));
        }
        req.decodedToken = decoded;
        next();
    });

});

io.on("connection", (socket) => {
    console.log(`connected with transport ${socket.conn.transport.name} and socket ${socket.id}`);

    socket.conn.on("upgrade", (transport) => {
        console.log(`transport upgraded to ${transport.name}`);
    });

    socket.on("disconnect", (reason) => {
        console.log(`disconnected ${socket.id} due to ${reason}`);
    });

    if(socket.request.decodedToken){
        let user_id = parseInt(socket.request.decodedToken.sub)
        socket.join(user_id);
    }
});

redis.subscribe("actions", (err, count) => {
    if (err) console.error(err.message);
    console.log(`Subscribed to ${count} channels.`);
});

redis.on("message", function (channel, data) {
    data = JSON.parse(data).data;
    io.to(data.user_id).emit(data.action, data);
    console.log(`send new message to user ${data.user_id} in the channel '${channel}'.`);
});
