import { eq } from "drizzle-orm";
import { Outlet, redirect } from "react-router";

import Footer from "~/components/Footer";
import Header from "~/components/Header";
import { users } from "~/server/db/schema";
import { Capabilities } from "~/server/web/roles";

import { Route } from "./+types/shell";

// This loads the bare minimum for the application to function
// So we know that if context fails to load then well, oops?
export async function loader({ request, context }: Route.LoaderArgs) {
  try {
    const session = await context.sessions.auth(request);
    if (
      typeof context.oidc === "object" &&
      session.user.subject !== "unknown-non-oauth" &&
      !request.url.endsWith("/onboarding")
    ) {
      const [user] = await context.db
        .select()
        .from(users)
        .where(eq(users.sub, session.user.subject))
        .limit(1);

      if (!user?.onboarded) {
        return redirect("/onboarding");
      }
    }

    const api = context.hsApi.getRuntimeClient(session.api_key);
    const check = await context.sessions.check(request, Capabilities.ui_access);

    // OIDC users without ui_access go to pending approval
    if (
      !check &&
      session.user.subject !== "unknown-non-oauth" &&
      !request.url.endsWith("/onboarding")
    ) {
      return redirect("/pending-approval");
    }

    return {
      config: context.hs.c,
      url: context.config.headscale.public_url ?? context.config.headscale.url,
      configAvailable: context.hs.readable(),
      debug: context.config.debug,
      user: session.user,
      access: {
        ui: check,
        dns: await context.sessions.check(request, Capabilities.read_network),
        users: await context.sessions.check(request, Capabilities.read_users),
        policy: await context.sessions.check(request, Capabilities.read_policy),
        machines: await context.sessions.check(request, Capabilities.read_machines),
        settings: await context.sessions.check(request, Capabilities.read_feature),
      },
      onboarding: request.url.endsWith("/onboarding"),
      healthy: await api.isHealthy(),
    };
  } catch {
    return redirect("/login", {
      headers: {
        "Set-Cookie": await context.sessions.destroySession(),
      },
    });
  }
}

export default function Shell({ loaderData }: Route.ComponentProps) {
  return (
    <>
      <Header {...loaderData} />
      <Outlet />
      <Footer {...loaderData} />
    </>
  );
}
