import { describe, expect, it } from 'vitest'
import { buildLoopbackUrl, dialLoopback, type RawWs, type WsConstructor } from '../src/transport/loopback.js'

describe('buildLoopbackUrl (T8)', () => {
  it('joins target + path without a double slash', () => {
    expect(buildLoopbackUrl('ws://127.0.0.1:3000', '/term?join=x')).toBe('ws://127.0.0.1:3000/term?join=x')
    expect(buildLoopbackUrl('ws://127.0.0.1:3000/', 'term')).toBe('ws://127.0.0.1:3000/term')
  })
})

class FakeRawWs implements RawWs {
  static last: FakeRawWs | null = null
  readonly url: string
  readonly origin: string | undefined
  private readonly handlers = new Map<string, (...a: unknown[]) => void>()
  constructor(url: string, opts?: { headers?: Record<string, string> }) {
    this.url = url
    this.origin = opts?.headers?.['Origin']
    FakeRawWs.last = this
  }
  send(): void {}
  close(): void {}
  on(): void {}
  once(event: string, cb: (...a: unknown[]) => void): void {
    this.handlers.set(event, cb)
  }
  fire(event: string, ...args: unknown[]): void {
    this.handlers.get(event)?.(...args)
  }
}

describe('dialLoopback (T8)', () => {
  it('replays Origin and resolves on open', async () => {
    const dial = dialLoopback('ws://127.0.0.1:3000', FakeRawWs as unknown as WsConstructor)
    const promise = dial('/term?join=x', 'https://host-42.term.example.com')
    FakeRawWs.last!.fire('open')
    const ws = await promise
    expect(FakeRawWs.last!.url).toBe('ws://127.0.0.1:3000/term?join=x')
    expect(FakeRawWs.last!.origin).toBe('https://host-42.term.example.com')
    expect(ws).toBeDefined()
  })

  it('rejects on a pre-open error (base app down)', async () => {
    const dial = dialLoopback('ws://127.0.0.1:3000', FakeRawWs as unknown as WsConstructor)
    const promise = dial('/term', 'https://x')
    FakeRawWs.last!.fire('error', new Error('ECONNREFUSED'))
    await expect(promise).rejects.toThrow('ECONNREFUSED')
  })
})
