/**
 * Module SSH Terminal - Gestion des connexions SSH via WebSocket
 * Utilise la bibliothèque ssh2 pour établir des connexions SSH
 */
const { Client } = require('ssh2');
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');
const config = require('./config');

/**
 * Initialise le serveur WebSocket SSH sur /ws-ssh
 * @param {http.Server} server - Le serveur HTTP Express
 */
function initSSHWebSocket(server) {
  const wssSsh = new WebSocket.Server({ server, path: '/ws-ssh' });

  wssSsh.on('connection', (ws, req) => {
    // Vérifier l'authentification via le token dans l'URL
    const url = new URL(req.url, 'http://localhost');
    const token = url.searchParams.get('token');

    if (!token) {
      ws.send(JSON.stringify({ type: 'error', message: 'Token manquant' }));
      ws.close();
      return;
    }

    try {
      jwt.verify(token, config.jwtSecret);
    } catch (err) {
      ws.send(JSON.stringify({ type: 'error', message: 'Token invalide' }));
      ws.close();
      return;
    }

    console.log('Nouvelle connexion WebSocket SSH');

    let sshClient = null;
    let sshStream = null;
    let connected = false;

    ws.on('message', (data) => {
      try {
        const msg = JSON.parse(data.toString());

        switch (msg.type) {
          case 'connect':
            // Établir la connexion SSH
            handleConnect(ws, msg, (client, stream) => {
              sshClient = client;
              sshStream = stream;
              connected = true;
            });
            break;

          case 'input':
            // Envoyer des données au terminal SSH
            if (sshStream && connected) {
              sshStream.write(msg.data);
            }
            break;

          case 'resize':
            // Redimensionner le terminal
            if (sshStream && connected) {
              sshStream.setWindow(msg.rows, msg.cols, 0, 0);
            }
            break;

          case 'disconnect':
            // Fermer la connexion SSH
            if (sshClient) {
              sshClient.end();
            }
            break;

          default:
            console.warn('Type de message SSH inconnu:', msg.type);
        }
      } catch (err) {
        console.error('Erreur parsing message SSH:', err.message);
      }
    });

    ws.on('close', () => {
      console.log('Connexion WebSocket SSH fermée');
      if (sshClient) {
        sshClient.end();
      }
    });

    ws.on('error', (err) => {
      console.error('Erreur WebSocket SSH:', err.message);
      if (sshClient) {
        sshClient.end();
      }
    });
  });

  console.log('Serveur WebSocket SSH initialisé sur /ws-ssh');
  return wssSsh;
}

/**
 * Gère la connexion SSH
 */
function handleConnect(ws, msg, onConnected) {
  const { host, port, username, password, privateKey } = msg;

  if (!host || !username) {
    ws.send(JSON.stringify({ type: 'error', message: 'Hôte et utilisateur requis' }));
    return;
  }

  const sshClient = new Client();

  const connConfig = {
    host: host,
    port: port || 22,
    username: username,
    readyTimeout: 15000,
    keepaliveInterval: 10000,
  };

  if (privateKey) {
    connConfig.privateKey = privateKey;
  } else if (password) {
    connConfig.password = password;
  } else {
    ws.send(JSON.stringify({ type: 'error', message: 'Mot de passe ou clé privée requis' }));
    return;
  }

  ws.send(JSON.stringify({ type: 'status', message: `Connexion à ${username}@${host}:${port || 22}...` }));

  sshClient.on('ready', () => {
    ws.send(JSON.stringify({ type: 'connected', message: `Connecté à ${host}` }));

    sshClient.shell({ term: 'xterm-256color', rows: 24, cols: 80 }, (err, stream) => {
      if (err) {
        ws.send(JSON.stringify({ type: 'error', message: `Erreur shell: ${err.message}` }));
        sshClient.end();
        return;
      }

      onConnected(sshClient, stream);

      // Transmettre les données du terminal SSH vers le WebSocket
      stream.on('data', (data) => {
        if (ws.readyState === WebSocket.OPEN) {
          ws.send(JSON.stringify({ type: 'output', data: data.toString('base64') }));
        }
      });

      stream.stderr.on('data', (data) => {
        if (ws.readyState === WebSocket.OPEN) {
          ws.send(JSON.stringify({ type: 'output', data: data.toString('base64') }));
        }
      });

      stream.on('close', () => {
        ws.send(JSON.stringify({ type: 'disconnected', message: 'Session SSH terminée' }));
        sshClient.end();
      });
    });
  });

  sshClient.on('error', (err) => {
    ws.send(JSON.stringify({ type: 'error', message: `Erreur SSH: ${err.message}` }));
  });

  sshClient.on('end', () => {
    ws.send(JSON.stringify({ type: 'disconnected', message: 'Connexion SSH fermée' }));
  });

  sshClient.connect(connConfig);
}

module.exports = { initSSHWebSocket };
