import Pool from 'socket-pool';

import connection from './connection';

export default class connection_pool {
  constructor(pool_size, host_or_ip, port, password) {
    this.host_or_ip = host_or_ip;
    this.port = port;
    this.password = password;
    if (pool_size > 1) {
      this.pool = new Pool({
        connect: { host: host_or_ip, port: port },
        connectTimeout: 5000,
        pool: { max: pool_size, min: 2 },
      });
    } else {
      throw new Error("'pool_size' must be > 1");
    }
  }

  host_or_ip = '';
  next_thread_id = 1;
  password = '';
  port = 20000;
  pool;
  shutdown = false;

  async disconnect() {
    await this.pool._pool.drain();
    await this.pool._pool.clear();
    this.pool = null;
    this.shutdown = true;
  }

  async send(method_name, packet, optional_thread_id) {
    try {
      const socket = await this.pool.acquire();
      if (!socket.thread_id) {
        socket.thread_id = this.next_thread_id++;
      }

      const cleanup = () => {
        try {
          socket.release();
        } catch (err) {
          console.log(`'release()' failed: ${err}`);
        }
      };

      try {
        const result = await new connection(
          this.host_or_ip,
          this.port,
          this.password,
          socket
        ).send(method_name, packet, optional_thread_id || socket.thread_id);
        cleanup();
        return result;
      } catch (err) {
        cleanup();
        return Promise.reject(
          new Error(`'send(${method_name})' failed: ${err}`)
        );
      }
    } catch (err) {
      return Promise.reject(new Error(`'acquire()' socket failed: ${err}`));
    }
  }
}
