import { type Server } from "bun";
import { expect, test, beforeAll, afterAll } from "bun:test";

import { server as app } from "../src/app";

const port = 33000;
const base = `http://localhost:${port}/`;
let server: Server;

beforeAll(async function () {
  server = Bun.serve(Object.assign({}, app, { port }));
});

afterAll(function () {
  server.stop();
});

test("/ returns 200", async function () {
  const res = await fetch(base);
  expect(res.status).toBe(200);
});

test("/asdf returns 404", async function () {
  const res = await fetch(`${base}asdf`);
  expect(res.status).toBe(404);
});

test("/ returns 304 with newer if-modified-since header", async function () {
  const res = await fetch(base, {
    headers: {
      "if-modified-since": new Date().toUTCString(),
    },
  });
  expect(res.status).toBe(304);
  expect(res.headers.get("vary")).toBe("Accept-Encoding");
});

test("/ returns 200 with older if-modified-since header", async function () {
  const res = await fetch(base, {
    headers: {
      "if-modified-since": new Date(0).toUTCString(),
    },
  });
  expect(res.status).toBe(200);
});

test("/ returns gzipped content with accept-encoding: gzip", async function () {
  const res = await fetch(base, {
    headers: {
      "accept-encoding": "gzip",
    },
  });
  expect(res.status).toBe(200);
  // Bun 0.8.1 this doesn't work, but `verbose` shows it's there
  // expect(res.headers.get("content-encoding")).toBe("gzip");
  // response is automatically gunzipped
  const body = await res.text();
  expect(body.length).toBeGreaterThan(
    Number(res.headers.get("content-length")),
  );
});

test("/ returns uncompressed content with accept-encoding: identity", async function () {
  const res = await fetch(base, {
    headers: {
      "accept-encoding": "identity",
    },
  });
  expect(res.status).toBe(200);
  const body = await res.text();
  expect(body.length).toBe(Number(res.headers.get("content-length")));
});

test("/ returns brotli-compressed content with accept-encoding: br", async function () {
  const res = await fetch(base, {
    headers: {
      "accept-encoding": "br",
    },
  });
  expect(res.status).toBe(200);
  expect(res.headers.get("content-encoding")).toBe("br");
  const body = await res.text();
  expect(body.length).toBeLessThan(Number(res.headers.get("content-length")));
});

test("/ returns zstd-compressed content with accept-encoding: zstd", async function () {
  const res = await fetch(base, {
    headers: {
      "accept-encoding": "zstd",
    },
  });
  expect(res.status).toBe(200);
  expect(res.headers.get("content-encoding")).toBe("zstd");
  expect(res.headers.get("vary")).toBe("Accept-Encoding");
  const body = await res.text();
  expect(body.length).toBeLessThan(Number(res.headers.get("content-length")));
});