'use strict'

const { once } = require('node:events')
const http = require('node:http')
const { test, describe } = require('node:test')
const { EventSource } = require('../../lib/web/eventsource/eventsource')

describe('EventSource - redirecting', () => {
  [301, 302, 307, 308].forEach((statusCode) => {
    test(`Should redirect on ${statusCode} status code`, async (t) => {
      const server = http.createServer({ joinDuplicateHeaders: true }, (req, res) => {
        if (res.req.url === '/redirect') {
          res.writeHead(statusCode, undefined, { Location: '/target' })
          res.end()
        } else if (res.req.url === '/target') {
          res.writeHead(200, 'dummy', { 'Content-Type': 'text/event-stream' })
          res.end()
        }
      })

      await once(server.listen(0), 'listening')

      const port = server.address().port

      const eventSourceInstance = new EventSource(`http://localhost:${port}/redirect`)
      eventSourceInstance.onerror = (e) => {
        t.assert.fail('Should not have errored')
      }
      eventSourceInstance.onopen = () => {
        t.assert.strictEqual(eventSourceInstance.url, `http://localhost:${port}/redirect`)
        eventSourceInstance.close()
        server.close()
      }
    })
  })

  test('Stop trying to connect when getting a 204 response', async (t) => {
    const server = http.createServer({ joinDuplicateHeaders: true }, (req, res) => {
      if (res.req.url === '/redirect') {
        res.writeHead(301, undefined, { Location: '/target' })
        res.end()
      } else if (res.req.url === '/target') {
        res.writeHead(204, 'OK')
        res.end()
      }
    })

    await once(server.listen(0), 'listening')
    const port = server.address().port

    const eventSourceInstance = new EventSource(`http://localhost:${port}/redirect`)
    eventSourceInstance.onerror = (event) => {
      t.assert.strictEqual(eventSourceInstance.url, `http://localhost:${port}/redirect`)
      t.assert.strictEqual(eventSourceInstance.readyState, EventSource.CLOSED)
      server.close()
    }
    eventSourceInstance.onopen = () => {
      t.assert.fail('Should not have opened')
    }
  })

  test('Throw when missing a Location header', async (t) => {
    const server = http.createServer({ joinDuplicateHeaders: true }, (req, res) => {
      if (res.req.url === '/redirect') {
        res.writeHead(301, undefined)
        res.end()
      } else if (res.req.url === '/target') {
        res.writeHead(204, 'OK')
        res.end()
      }
    })

    await once(server.listen(0), 'listening')
    const port = server.address().port

    const eventSourceInstance = new EventSource(`http://localhost:${port}/redirect`)
    eventSourceInstance.onerror = () => {
      t.assert.strictEqual(eventSourceInstance.url, `http://localhost:${port}/redirect`)
      t.assert.strictEqual(eventSourceInstance.readyState, EventSource.CLOSED)
      server.close()
    }
  })

  test('Should set origin attribute of messages after redirecting', async (t) => {
    const targetServer = http.createServer({ joinDuplicateHeaders: true }, (req, res) => {
      if (res.req.url === '/target') {
        res.writeHead(200, undefined, { 'Content-Type': 'text/event-stream' })
        res.write('event: message\ndata: test\n\n')
      }
    })

    await once(targetServer.listen(0), 'listening')
    const targetPort = targetServer.address().port

    const sourceServer = http.createServer({ joinDuplicateHeaders: true }, (req, res) => {
      res.writeHead(301, undefined, { Location: `http://127.0.0.1:${targetPort}/target` })
      res.end()
    })

    await once(sourceServer.listen(0), 'listening')
    const sourcePort = sourceServer.address().port

    const eventSourceInstance = new EventSource(`http://127.0.0.1:${sourcePort}/redirect`)
    eventSourceInstance.onmessage = (event) => {
      t.assert.strictEqual(event.origin, `http://127.0.0.1:${targetPort}`)
      eventSourceInstance.close()
      targetServer.close()
      sourceServer.close()
    }
    eventSourceInstance.onerror = (e) => {
      t.assert.fail('Should not have errored')
    }
  })
})
