import net from 'net'
import { URL } from 'url'
import { ProxyConnectionOptions } from './ConnectionManager.js'
import { DirectConnection } from './DirectConnection.js'
import { SerializableError } from '../../../models/SerializableError.js'

/**
 * Handles HTTP requests through a proxy server
 */
export class ProxyConnection {
  private options: ProxyConnectionOptions

  constructor(options: ProxyConnectionOptions) {
    this.options = options
  }

  /**
   * Establish a connection to the proxy server
   */
  async connect(): Promise<net.Socket> {
    const { proxy, proxyIsSsl, logger } = this.options

    logger.debug('Proxying an HTTP request...')

    if (!proxy) {
      throw new Error('No proxy configuration found.')
    }

    let proxyUrl = proxy
    if (proxyIsSsl && !proxyUrl.startsWith('https:')) {
      proxyUrl = `https://${proxyUrl}`
    } else if (!proxyIsSsl && !proxyUrl.startsWith('http:')) {
      proxyUrl = `http://${proxyUrl}`
    }

    const proxyUri = new URL(proxyUrl)
    const port = Number(proxyUri.port || (proxyIsSsl ? 443 : 80))
    const host = proxyUri.hostname

    // Create a direct connection to the proxy
    const directConnection = new DirectConnection({
      ...this.options,
      host,
      port,
      protocol: proxyIsSsl ? 'https:' : 'http:',
    })

    try {
      return await directConnection.connect()
    } catch (error) {
      const err = error as Error & { code?: string }
      throw new SerializableError(`Failed to connect to proxy: ${err.message}`, err.code ? Number(err.code) : 112)
    }
  }
}
