import { test, expect, beforeAll, afterAll } from "bun:test"
import { Hype } from "../index.tsx"
import { join } from "path"
import { mkdirSync, writeFileSync, rmSync } from "fs"

// PWD is set to testRoot, so pages resolve at testRoot/src/pages/
const testRoot = join(process.cwd(), "src/tests/_test_root")
const pagesDir = join(testRoot, "src/pages")

beforeAll(() => {
  mkdirSync(join(pagesDir, "editor"), { recursive: true })
  mkdirSync(join(pagesDir, "deep/nested"), { recursive: true })

  writeFileSync(join(pagesDir, "index.tsx"), `export default <h1>Home</h1>`)
  writeFileSync(join(pagesDir, "about.tsx"), `export default <h1>About</h1>`)
  writeFileSync(join(pagesDir, "editor/spell.tsx"), `export default <h1>Spell Editor</h1>`)
  writeFileSync(join(pagesDir, "deep/nested/page.tsx"), `export default <h1>Deep Page</h1>`)
  writeFileSync(join(pagesDir, "editor/index.tsx"), `export default <h1>Editor Index</h1>`)
  writeFileSync(join(pagesDir, "_private.tsx"), `export default <h1>Private</h1>`)
  writeFileSync(join(pagesDir, "editor/_secret.tsx"), `export default <h1>Secret</h1>`)
})

afterAll(() => {
  rmSync(testRoot, { recursive: true, force: true })
})

test("single-segment page route", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/about`)
  const text = await res.text()
  expect(res.status).toBe(200)
  expect(text).toContain("About")

  server.stop(true)
  process.env.PWD = origPwd
})

test("nested page route (editor/spell)", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/editor/spell`)
  const text = await res.text()
  expect(res.status).toBe(200)
  expect(text).toContain("Spell Editor")

  server.stop(true)
  process.env.PWD = origPwd
})

test("deeply nested page route", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/deep/nested/page`)
  const text = await res.text()
  expect(res.status).toBe(200)
  expect(text).toContain("Deep Page")

  server.stop(true)
  process.env.PWD = origPwd
})

test("subdirectory index.tsx fallback", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/editor`)
  const text = await res.text()
  expect(res.status).toBe(200)
  expect(text).toContain("Editor Index")

  server.stop(true)
  process.env.PWD = origPwd
})

test("underscore-prefixed files return 404", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/_private`)
  expect(res.status).toBe(404)

  server.stop(true)
  process.env.PWD = origPwd
})

test("underscore-prefixed files in subdirectories return 404", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/editor/_secret`)
  expect(res.status).toBe(404)

  server.stop(true)
  process.env.PWD = origPwd
})

test("nonexistent page returns 404", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/does/not/exist`)
  expect(res.status).toBe(404)

  server.stop(true)
  process.env.PWD = origPwd
})

test("path traversal is blocked", async () => {
  const origPwd = process.env.PWD
  process.env.PWD = testRoot
  const app = new Hype({ layout: false, logging: false, prettyHTML: false })
  const server = Bun.serve({ port: 0, fetch: app.defaults.fetch })

  const res = await fetch(`http://localhost:${server.port}/../../../etc/passwd`)
  expect(res.status).toBe(404)

  server.stop(true)
  process.env.PWD = origPwd
})
