import type { Action, Loader } from "./main"

export const renderServer = async (req: Request, route: Bun.MatchedRoute) => {
  const contentType = req.headers.get("Content-Type")

  if (contentType?.startsWith("multipart/form-data;")) {
    return await handleAction(req, route)
  } else {
    return await renderHtml(req, route)
  }
}

const handleAction = async (req: Request, route: Bun.MatchedRoute) => {
  const { action, loader } = (await import(route.filePath)) as {
    action: Action
    loader?: Loader<any>
  }

  if (typeof action !== "function") {
    return Response.json(
      { error: `Route at "${route.pathname}" does not export an "action" function` },
      { status: 400 }
    )
  }

  const actionData = await action(req, route.params)
  if (actionData instanceof Response) return actionData // This should only happen if the action wants to redirect
  const loaderData = await loader?.(req, route.params)
  const result = { actionData, loaderData }

  return new Response(JSON.stringify(result), {
    status: 200,
    headers: { "Content-Type": "application/json" },
  })
}

const renderHtml = async (req: Request, route: Bun.MatchedRoute) => {
  const component = await import(route.filePath)
  const loader = component.loader as Loader<any>
  const loaderData = loader ? await loader(req, route.params) : {}

  const routeName = route.name === "/" ? "/index" : route.name

  // Remove any < characters from the loader data to prevent XSS attacks
  const escapedLoaderData = JSON.stringify(loaderData).replace(/</g, "\\u003c")
  const headLinks = component.head?.links?.map((attrs: any) => <link {...attrs} />)
  const headScripts = component.head?.scripts?.map((attrs: any) => <script {...attrs} />)
  return new Response(
    `<!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <link rel="stylesheet" href="${routeName + ".css"}" />
          <title>${component.head?.title ?? "Untitled"}</title>
          ${headLinks?.join("\n") ?? ""}
          ${headScripts?.join("\n") ?? ""}
          <script id="__LOADER_DATA__" type="application/json">${escapedLoaderData}</script>
        </head>
        <body>
          <div id="root">${component.default(loaderData)}</div>
          <script type="module" src="${routeName + ".js"}"></script>
        </body>
      </html>`,
    {
      headers: {
        "Content-Type": "text/html; charset=utf-8",
      },
    }
  )
}
