const jwt = require('jsonwebtoken');
const pool = require('../db');

const onlineUsers = require('./onlineUsers');
const initChatSockets = require('./chat.socket');
const { registerProjectRoomSockets } = require('./projectRooms.socket');

/* ============================================================
   HELPERS
============================================================ */

/**
 * Returns project IDs the user belongs to within the org
 * Authoritative source: DB
 */
async function getUserProjectIds({ userId, orgId }) {
  const [rows] = await pool.query(`
    SELECT pu.projectId
    FROM project_users pu
    JOIN projects p ON p.id = pu.projectId
    WHERE pu.userId = ?
      AND p.organizationId = ?
  `, [userId, orgId]);

  return rows.map(r => r.projectId);
}

/* ============================================================
   SOCKET INITIALIZER
============================================================ */

module.exports = function initSockets(io) {

  // 🔒 Defensive: ensure this runs only once per IO
  if (io.__chatInitialized) {
    console.warn('⚠️ initSockets called more than once on same io instance');
    return;
  }
  io.__chatInitialized = true;

  io.on('connection', async (socket) => {
    console.log('SERVER socket connected:', socket.id, socket.nsp.name);

    try {
      const token = socket.handshake.auth?.token;
      if (!token) {
        console.warn('SERVER socket missing token:', socket.id);
        socket.disconnect(true);
        return;
      }

      const payload = jwt.verify(token, process.env.JWT_SECRET);

      socket.user = {
        userId: Number(payload.userId),
        orgId: Number(payload.organizationId),
        role: payload.role
      };

      const { userId, orgId } = socket.user;

      if (!userId || !orgId) {
        console.warn('SERVER invalid socket identity:', socket.id);
        socket.disconnect(true);
        return;
      }

      /* -------------------------
         JOIN ORG ROOM
      -------------------------- */
      socket.join(`org:${orgId}`);

      /* -------------------------
         JOIN PROJECT ROOMS (STEP 1)
      -------------------------- */
      try {
        const projectIds = await getUserProjectIds({ userId, orgId });

        projectIds.forEach(projectId => {
          const room = `org:${orgId}:project:${projectId}`;
          socket.join(room);
        });

        console.log(
          `[SOCKET] user ${userId} joined ${projectIds.length} project rooms`
        );
      } catch (err) {
        console.error(
          `[SOCKET] failed to join project rooms for user ${userId}`,
          err
        );
      }

      /* -------------------------
         PRESENCE: CONNECT
      -------------------------- */
      onlineUsers.add(orgId, userId, socket.id);

      await pool.query(
        'UPDATE users SET is_online = 1 WHERE id = ? AND organizationId = ?',
        [userId, orgId]
      );

      io.to(`org:${orgId}`).emit('presence_changed', {
        userId,
        isOnline: true
      });

      /* -------------------------
         CHAT HANDLERS (CRITICAL)
      -------------------------- */
      console.log('SERVER binding chat.socket.js to:', socket.id);
      initChatSockets(io, socket);

      /* -------------------------
         PROJECT ROOM HANDLERS
      -------------------------- */
      registerProjectRoomSockets(io, socket);


      /* -------------------------
         DISCONNECT
      -------------------------- */
      socket.on('disconnect', async () => {
        console.log('SERVER socket disconnected:', socket.id);

        onlineUsers.remove(orgId, userId, socket.id);

        if (!onlineUsers.isUserOnline(orgId, userId)) {
          await pool.query(
            'UPDATE users SET is_online = 0, last_seen = NOW() WHERE id = ? AND organizationId = ?',
            [userId, orgId]
          );

          io.to(`org:${orgId}`).emit('presence_changed', {
            userId,
            isOnline: false
          });
        }
      });

      // 🔍 TEMP: see every event from this socket
      socket.onAny((event) => {
        console.log('SERVER received event:', event, 'from', socket.id);
      });

    } catch (err) {
      console.error('Socket auth failed:', err.message);
      socket.disconnect(true);
    }
  });
};
