import { getPort } from '../src/testing/getPort.js'
import { ExpressServer } from '../tests/servers/ExpressServer.js'
import { ProxyServer } from '../tests/servers/ProxyServer.js'
import SSLServer from '../tests/servers/ssl.js'
import { SetupHttpConfig } from './context.js'

export enum State {
  initializing = 'initializing',
  started = 'started',
  stopped = 'stopped',
}

/**
 * A set of servers for library testing.
 */
export default class {
  /**
   * The state of the server.
   */
  state = State.initializing
  /**
   * The express server to test HTTP engine.
   */
  #server = new ExpressServer()
  /**
   * The proxy server to test request proxying and project runners.
   */
  #proxy = new ProxyServer()
  /**
   * Used to test out client certificates.
   * TODO: Replace it with an express route, if possible.
   */
  #ssl = new SSLServer()
  /**
   * Port for the SSL server.
   */
  #certPort = 0
  #httpPort = 0
  #httpsPort = 0
  #proxyHttpPort = 0
  #proxyHttpsPort = 0

  async start(): Promise<void> {
    if (this.state === State.started) {
      return
    }
    await this.#setupPorts()
    await this.#server.start(this.#httpPort, this.#httpsPort)
    await this.#ssl.start(this.#certPort)
    await this.#proxy.start(this.#proxyHttpPort, this.#proxyHttpsPort)
    // this.proxy.debug = true;
    this.state = State.started
  }

  async #setupPorts(): Promise<void> {
    this.#certPort = await getPort()
    this.#httpPort = await getPort()
    this.#httpsPort = await getPort()
    this.#proxyHttpPort = await getPort()
    this.#proxyHttpsPort = await getPort()
  }

  async stop(): Promise<void> {
    if (this.state !== State.started) {
      return
    }
    await this.#server.stop()
    await this.#proxy.stop()
    await this.#ssl.stop()
    this.state = State.stopped
  }

  getConfig(): SetupHttpConfig {
    const info: SetupHttpConfig = {
      httpPort: this.#httpPort,
      httpsPort: this.#httpsPort,
      certsPort: this.#certPort,
      proxyHttpPort: this.#proxyHttpPort,
      proxyHttpsPort: this.#proxyHttpsPort,
    }
    return info
  }
}
