import React from "react";
// Database connection is now handled by the centralized db module
import { renderToString } from "react-dom/server";
import { AppShell } from "./src/frontend/AppShell";
import { Home } from "./src/frontend/pages/home";
import { NotFound } from "./src/frontend/pages/not-found";
import { Post } from "./src/frontend/pages/post";
import { dbConnection } from "./src/db";

function compressResponse(html: string, status?: number) {
  const compressed = Bun.gzipSync(Buffer.from(html));
  return new Response(compressed, {
    status,
    headers: {
      "Content-Type": "text/html",
      "Content-Encoding": "gzip",
      "Vary": "Accept-Encoding"
    }
  });
}

async function blogPosts(hmr: boolean) {
  const glob = new Bun.Glob("**/*.md");
  const blogPosts: Record<string, any> = {};
  for await (const file of glob.scan("./content")) {
    const post = await import(`./content/${file}`, { with: { type: "html" } });
    const route = `/${file.replace(/\.md$/, "")}`;
    dbConnection.getAllTags();

    if (hmr) {
      // Use Bun Importer plugin for hot reloading in the browser
      blogPosts[`/hmr${route}`] = post.default;
    } else {
      // Use the Database for sending just the HTML or the HTML and AppShell
      blogPosts[route] = async (req: Request) => {
        const path = new URL(req.url).pathname;
        const post = dbConnection.getPost(path);
        if (!post)
          return compressResponse(renderToString(<NotFound />), 404);

        // Get adjacent posts for navigation
        const { previousPost, nextPost } = dbConnection.getAdjacentPosts(post.path);

        const data = {
          title: post.title,
          summary: post.summary,
          date: new Date(post.date),
          readingTime: post.reading_time,
          tags: post.tags || [],
          previousPost,
          nextPost,
        };

        // AppShell is already loaded, just send the <main> content
        if (req.headers.get("shell-loaded") === "true") {
          return compressResponse(
            renderToString(<Post meta={data} children={post.content} />)
          );
        }

        // AppShell is not loaded, send the <AppShell> with the <main> content inside
        return compressResponse(
          renderToString(
            <AppShell>
              <Post
                meta={data}
                children={post.content}
              />
            </AppShell>,
          )
        );
      };
    }
  }

  Object.keys(blogPosts).map((route) => {
    console.info(route);
  });
  return blogPosts;
}

Bun.serve({
  development: {
    hmr: true,
    console: true,
  },

  routes: {
    // standard mounting of blog posts
    ...(await blogPosts(false)),

    // hot module replacement in development mode
    ...(process.env.NODE_ENV === "development" ? (await blogPosts(true)) : {}),

    // Home page
    "/": (req: Request) => {
      // Extract URL parameters from the request to pass to the component
      const searchParams = new URLSearchParams(req.url.split('?')[1]);

      if (req.headers.get("shell-loaded") === "true") {
        return compressResponse(renderToString(<Home searchParams={searchParams} />));
      }

      return compressResponse(
        renderToString(
          <AppShell searchParams={searchParams}>
            <Home searchParams={searchParams} />
          </AppShell>,
        )
      );
    },
    "/profile-picture.webp": () => {
      return new Response(Bun.file("./src/public/profile-picture.webp"), {
        headers: {
          "Content-Type": "image/webp",
        },
      });
    },
    "/healthz": new Response('ok'),
    "/*": (req) => {
      if(req.headers.get("shell-loaded") === "true") {
        return compressResponse(renderToString(<NotFound />), 404);
      }
      return compressResponse(renderToString(<AppShell><NotFound /></AppShell>), 404);
    }
  },
});
