<script lang="ts">
  import { Link, usePoll } from "@inertiajs/svelte";
  import Button from "../components/Button.svelte";
  import CountryFlag from "../components/CountryFlag.svelte";
  import Modal from "../components/Modal.svelte";
  import type { Snippet } from "svelte";
  import { onMount, onDestroy } from "svelte";
  import plur from "plur";
  import { streakTheme, streakLabel } from "../utils";

  type NavLink = {
    label: string;
    href?: string;
    active?: boolean;
    badge?: number | null;
    action?: string;
    inertia?: boolean;
  };

  type AdminLevel = "default" | "superadmin" | "admin" | "viewer";

  type NavCurrentUser = {
    display_name: string;
    avatar_url?: string | null;
    title: string;
    country_code?: string | null;
    country_name?: string | null;
    streak_days?: number | null;
    admin_level: AdminLevel;
  };

  type LayoutNav = {
    flash: { message: string; class_name: string }[];
    user_present: boolean;
    current_user?: NavCurrentUser | null;
    login_path: string;
    links: NavLink[];
    dev_links: NavLink[];
    admin_links: NavLink[];
    viewer_links: NavLink[];
    superadmin_links: NavLink[];
  };

  type Footer = {
    git_version: string;
    commit_link: string;
    server_start_time_ago: string;
    heartbeat_recent_count: number;
    heartbeat_recent_imported_count: number;
    query_count: number;
    query_cache_count: number;
    cache_hits: number;
    cache_misses: number;
    requests_per_second: string;
    active_users_graph: { height: number; users: number }[];
  };

  type CurrentlyHackingUser = {
    id: number;
    display_name?: string;
    slack_uid?: string;
    avatar_url?: string;
    active_project?: { name: string; repo_url?: string | null };
  };

  type LayoutProps = {
    nav: LayoutNav;
    footer: Footer;
    theme: {
      name: string;
      color_scheme: "dark" | "light";
      theme_color: string;
    };
    currently_hacking: {
      count: number;
      users: CurrentlyHackingUser[];
      interval: number;
    };
    csrf_token: string;
    signout_path: string;
    show_stop_impersonating: boolean;
    stop_impersonating_path: string;
  };

  let { layout, children }: { layout: LayoutProps; children?: Snippet } =
    $props();

  const isBrowser =
    typeof window !== "undefined" && typeof document !== "undefined";

  let navOpen = $state(false);
  let logoutOpen = $state(false);
  let currentlyExpanded = $state(false);
  let flashVisible = $state(false);
  let flashHiding = $state(false);
  const flashHideDelay = 6000;
  const flashExitDuration = 250;
  const currentlyHackingPollInterval = () =>
    layout.currently_hacking?.interval || 30000;

  const toggleNav = () => (navOpen = !navOpen);
  const closeNav = () => (navOpen = false);
  const openLogout = () => (logoutOpen = true);
  const closeLogout = () => (logoutOpen = false);

  usePoll(currentlyHackingPollInterval(), {
    only: ["currently_hacking"],
  });

  const handleNavLinkClick = () => {
    if (isBrowser && window.innerWidth <= 1024) closeNav();
  };

  const handleResize = () => {
    if (isBrowser && window.innerWidth > 1024) closeNav();
  };

  const handleKeydown = (e: KeyboardEvent) => {
    if (e.key === "Escape") {
      closeNav();
      closeLogout();
    }
  };

  const countLabel = () =>
    `${layout.currently_hacking.count} ${plur("person", layout.currently_hacking.count)} currently hacking`;

  const visualizeGitUrl = (url?: string | null) =>
    url?.startsWith("https://github.com/")
      ? url.replace(
          "https://github.com/",
          "https://tkww0gcc0gkwwo4gc8kgs0sw.a.selfhosted.hackclub.com/",
        )
      : "";

  const latinPhrases = [
    "carpe diem",
    "nemo sine vitio est",
    "docendo discimus",
    "per aspera ad astra",
    "ex nihilo nihil",
    "aut viam inveniam aut faciam",
    "semper ad mellora",
    "soli fortes, una fortiores",
    "nulla tenaci invia est via",
    "nihil boni sine labore",
  ];

  const activeUsersGraphTitle = (hourIndex: number, users: number) => {
    const hoursAgo = hourIndex + 1;
    const phrase = latinPhrases[(hoursAgo + users) % latinPhrases.length];
    return `${hoursAgo} ${plur("hour", hoursAgo)} ago, ${users} ${plur("person", users)} logged time. '${phrase}.'`;
  };

  const footerStatsText = () =>
    `${layout.footer.heartbeat_recent_count} ${plur("heartbeat", layout.footer.heartbeat_recent_count)} (${layout.footer.heartbeat_recent_imported_count} imported) in the past 24 hours. (DB: ${layout.footer.query_count} ${plur("query", layout.footer.query_count)}, ${layout.footer.query_cache_count} cached) (CACHE: ${layout.footer.cache_hits} hits, ${layout.footer.cache_misses} misses) (${layout.footer.requests_per_second})`;

  const adminLevelLabel = (adminLevel?: AdminLevel | null) => {
    if (adminLevel === "superadmin") return "Superadmin";
    if (adminLevel === "admin") return "Admin";
    if (adminLevel === "viewer") return "Viewer";
    return null;
  };

  const adminLevelClass = (adminLevel?: AdminLevel | null) => {
    if (adminLevel === "superadmin") return "text-red superadmin-tool";
    if (adminLevel === "admin") return "text-yellow admin-tool";
    if (adminLevel === "viewer") return "text-blue viewer-tool";
    return "";
  };

  const toggleCurrentlyHacking = () => {
    currentlyExpanded = !currentlyExpanded;
  };

  $effect(() => {
    if (isBrowser) document.body.classList.toggle("overflow-hidden", navOpen);
  });

  $effect(() => {
    if (!isBrowser || !layout.theme?.name) return;

    document.documentElement.setAttribute("data-theme", layout.theme.name);

    const colorSchemeMeta = document.querySelector("meta[name='color-scheme']");
    colorSchemeMeta?.setAttribute("content", layout.theme.color_scheme);

    const themeColorMeta = document.querySelector("meta[name='theme-color']");
    themeColorMeta?.setAttribute("content", layout.theme.theme_color);

    const tileColorMeta = document.querySelector(
      "meta[name='msapplication-TileColor']",
    );
    tileColorMeta?.setAttribute("content", layout.theme.theme_color);
  });

  $effect(() => {
    if (!layout.nav.flash.length) {
      flashVisible = false;
      flashHiding = false;
      return;
    }

    flashVisible = true;
    flashHiding = false;
    let removeTimeoutId: ReturnType<typeof setTimeout> | undefined;
    const hideTimeoutId = setTimeout(() => {
      flashHiding = true;
      removeTimeoutId = setTimeout(() => {
        flashVisible = false;
        flashHiding = false;
      }, flashExitDuration);
    }, flashHideDelay);

    return () => {
      clearTimeout(hideTimeoutId);
      if (removeTimeoutId) clearTimeout(removeTimeoutId);
    };
  });

  onMount(() => {
    if (!isBrowser) return;
    handleResize();
    window.addEventListener("resize", handleResize);
    document.addEventListener("keydown", handleKeydown);
  });

  onDestroy(() => {
    if (isBrowser) {
      window.removeEventListener("resize", handleResize);
      document.removeEventListener("keydown", handleKeydown);
    }
  });

  const navLinkClass = (active?: boolean) =>
    `block px-3 py-2 rounded-md text-sm transition-colors ${active ? "bg-primary text-on-primary font-bold" : "text-surface-content hover:bg-darkless hover:text-primary"}`;
</script>

{#if flashVisible && layout.nav.flash.length > 0}
  <div
    class="fixed top-4 left-1/2 transform -translate-x-1/2 z-50 w-full max-w-md px-4 space-y-2"
  >
    {#each layout.nav.flash as item}
      <div
        class={`flash-message shadow-lg flash-message--enter ${flashHiding ? "flash-message--leaving" : ""} ${item.class_name}`}
      >
        {item.message}
      </div>
    {/each}
  </div>
{/if}

{#if layout.nav.user_present}
  <Button
    type="button"
    unstyled
    class="mobile-nav-button"
    aria-label="Toggle navigation menu"
    aria-expanded={navOpen}
    onclick={toggleNav}
  >
    <svg
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      viewBox="0 0 24 24"
      stroke="currentColor"
      aria-hidden="true"
    >
      <path
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="2"
        d="M4 6h16M4 12h16M4 18h16"
      />
    </svg>
  </Button>
  <button
    type="button"
    class="nav-overlay"
    class:open={navOpen}
    onclick={closeNav}
    aria-label="Close navigation menu"
  ></button>

  <aside
    class="flex flex-col min-h-screen w-52 bg-dark text-surface-content px-3 py-4 rounded-r-lg overflow-y-auto lg:block"
    data-nav-target="nav"
    class:open={navOpen}
    style="scrollbar-width: none; -ms-overflow-style: none;"
  >
    <div class="space-y-4">
      {#if layout.nav.user_present}
        <div
          class="flex flex-col items-center gap-2 pb-3 border-b border-darkless"
        >
          {#if layout.nav.current_user}
            <div
              class="user-info flex items-center gap-2"
              title={layout.nav.current_user.title}
            >
              {#if layout.nav.current_user.avatar_url}
                <img
                  src={layout.nav.current_user.avatar_url}
                  alt={`${layout.nav.current_user.display_name}'s avatar`}
                  width="32"
                  height="32"
                  class="rounded-full aspect-square border border-surface-200"
                  loading="lazy"
                />
              {/if}
              <span class="inline-flex items-center gap-1">
                {layout.nav.current_user.display_name}
              </span>
              {#if layout.nav.current_user.country_code}
                <span
                  class="flex items-center"
                  title={layout.nav.current_user.country_name ||
                    layout.nav.current_user.country_code}
                >
                  <CountryFlag
                    countryCode={layout.nav.current_user.country_code}
                    countryName={layout.nav.current_user.country_name}
                  />
                </span>
              {/if}
            </div>

            {#if layout.nav.current_user.streak_days && layout.nav.current_user.streak_days > 0}
              {@const streak = streakTheme(layout.nav.current_user.streak_days)}
              <div
                class={`inline-flex items-center gap-1 px-2 py-1 bg-gradient-to-r ${streak.bg} border ${streak.bc} rounded-lg transition-all duration-200 ${streak.hbg} group`}
                title={layout.nav.current_user.streak_days > 30
                  ? "30+ daily streak"
                  : `${layout.nav.current_user.streak_days} day streak`}
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  width="24"
                  height="24"
                  viewBox="0 0 24 24"
                  class={`${streak.ic} transition-colors duration-200 group-hover:animate-pulse`}
                >
                  <path
                    fill="currentColor"
                    d="M10 2c0-.88 1.056-1.331 1.692-.722c1.958 1.876 3.096 5.995 1.75 9.12l-.08.174l.012.003c.625.133 1.203-.43 2.303-2.173l.14-.224a1 1 0 0 1 1.582-.153C18.733 9.46 20 12.402 20 14.295C20 18.56 16.409 22 12 22s-8-3.44-8-7.706c0-2.252 1.022-4.716 2.632-6.301l.605-.589c.241-.236.434-.43.618-.624C9.285 5.268 10 3.856 10 2"
                  ></path>
                </svg>

                <span
                  class={`text-md font-semibold ${streak.tc} transition-colors duration-200`}
                >
                  {streakLabel(layout.nav.current_user.streak_days)}
                  <span class={`ml-1 font-normal ${streak.tm}`}>day streak</span
                  >
                </span>
              </div>
            {/if}

            {#if adminLevelLabel(layout.nav.current_user.admin_level)}
              <span
                class={`${adminLevelClass(layout.nav.current_user.admin_level)} font-semibold px-2`}
              >
                {adminLevelLabel(layout.nav.current_user.admin_level)}
              </span>
            {/if}
          {/if}
        </div>
      {:else}
        <div>
          <a
            href={layout.nav.login_path}
            class="block px-4 py-2 rounded-md transition text-on-primary font-semibold bg-primary hover:bg-secondary text-center"
            >Login</a
          >
        </div>
      {/if}

      <nav class="space-y-1">
        {#each layout.nav.links as link}
          {#if link.action === "logout"}
            <button
              type="button"
              onclick={openLogout}
              class={`${navLinkClass(false)} cursor-pointer w-full text-left`}
              >Logout</button
            >
          {:else if link.inertia}
            <Link
              href={link.href || "#"}
              onclick={handleNavLinkClick}
              class={navLinkClass(link.active)}>{link.label}</Link
            >
          {:else}
            <a
              href={link.href || "#"}
              onclick={handleNavLinkClick}
              class={navLinkClass(link.active)}>{link.label}</a
            >
          {/if}
        {/each}

        {#if layout.nav.dev_links.length > 0 || layout.nav.admin_links.length > 0 || layout.nav.viewer_links.length > 0 || layout.nav.superadmin_links.length > 0}
          <div class="pt-2 mt-2 border-t border-darkless space-y-1">
            {#each layout.nav.dev_links as link}
              {#if link.inertia}
                <Link
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} dev-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </Link>
              {:else}
                <a
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} dev-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </a>
              {/if}
            {/each}

            {#each layout.nav.admin_links as link}
              {#if link.inertia}
                <Link
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} admin-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </Link>
              {:else}
                <a
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} admin-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </a>
              {/if}
            {/each}

            {#each layout.nav.viewer_links as link}
              {#if link.inertia}
                <Link
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} viewer-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </Link>
              {:else}
                <a
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} viewer-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </a>
              {/if}
            {/each}

            {#each layout.nav.superadmin_links as link}
              {#if link.inertia}
                <Link
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} superadmin-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-white font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </Link>
              {:else}
                <a
                  href={link.href || "#"}
                  onclick={handleNavLinkClick}
                  class="{navLinkClass(link.active)} superadmin-tool"
                >
                  {link.label}
                  {#if link.badge}
                    <span
                      class="ml-1 px-1.5 py-0.5 text-xs rounded-full bg-primary text-on-primary font-medium"
                    >
                      {link.badge}
                    </span>
                  {/if}
                </a>
              {/if}
            {/each}
          </div>
        {/if}
      </nav>
    </div>
  </aside>
{/if}

<main
  class={`flex-1 min-h-screen transition-all duration-300 ease-in-out ${layout.nav.user_present ? "lg:ml-62.5" : ""}`}
>
  <div class="w-full max-w-7xl mx-auto p-4 pt-16 lg:pt-8 md:p-8">
    {@render children?.()}

    <footer
      class="relative w-full mt-12 mb-5 p-2.5 text-center text-xs text-text-muted"
    >
      <div class="container mx-auto">
        <p
          class="brightness-60 hover:brightness-100 transition-all duration-200"
        >
          Using Inertia. Build <a
            href={layout.footer.commit_link}
            class="text-inherit underline opacity-80 hover:opacity-100 transition-opacity duration-200"
            >{layout.footer.git_version}</a
          >
          from {layout.footer.server_start_time_ago} ago. {footerStatsText()}
        </p>
        {#if layout.show_stop_impersonating}
          <a
            href={layout.stop_impersonating_path}
            data-turbo-prefetch="false"
            class="text-primary font-bold hover:text-red transition-colors duration-200"
            >Stop impersonating</a
          >
        {/if}
      </div>
      <div class="flex flex-row gap-2 mt-4 justify-center">
        {#each layout.footer.active_users_graph as hour, hourIndex}
          <div
            class="bg-white opacity-10 grow max-w-1 rounded-sm"
            title={activeUsersGraphTitle(hourIndex, hour.users)}
            style={`height: ${hour.height}px`}
          ></div>
        {/each}
      </div>
    </footer>
  </div>
</main>

{#if layout.currently_hacking}
  <div
    class="fixed top-0 right-5 max-w-sm max-h-[80vh] bg-dark border border-darkless rounded-b-xl shadow-lg z-1000 overflow-hidden transform transition-transform duration-300 ease-out"
  >
    <button
      type="button"
      class="currently-hacking p-3 bg-dark cursor-pointer select-none flex items-center justify-between"
      onclick={toggleCurrentlyHacking}
      aria-expanded={currentlyExpanded}
      aria-label="Toggle currently hacking list"
    >
      <div class="text-surface-content text-sm font-medium">
        <div class="flex items-center">
          <div class="w-2 h-2 rounded-full bg-green animate-pulse mr-2"></div>
          <span class="text-base">{countLabel()}</span>
        </div>
      </div>
    </button>

    {#if currentlyExpanded}
      {#if layout.currently_hacking.users.length === 0}
        <div class="p-4 bg-dark">
          <div class="text-center text-muted text-sm italic">
            No one is currently hacking :(
          </div>
        </div>
      {:else}
        <div
          class="currently-hacking-list max-h-[60vh] max-w-100 overflow-y-auto p-2 bg-darker"
        >
          <div class="space-y-2">
            {#each layout.currently_hacking.users as user}
              <div
                class="flex flex-col space-y-1 p-2 rounded-md hover:bg-dark transition-colors"
              >
                <div class="flex items-center gap-2">
                  {#if user.avatar_url}
                    <img
                      src={user.avatar_url}
                      alt={`${user.display_name || `User ${user.id}`}'s avatar`}
                      class="w-6 h-6 rounded-full aspect-square flex-shrink-0"
                      loading="lazy"
                    />
                  {/if}
                  {#if user.slack_uid}
                    <a
                      href={`https://hackclub.slack.com/team/${user.slack_uid}`}
                      target="_blank"
                      class="text-blue hover:underline text-sm"
                    >
                      @{user.display_name || `User ${user.id}`}
                    </a>
                  {:else}
                    <span class="text-surface-content text-sm"
                      >{user.display_name || `User ${user.id}`}</span
                    >
                  {/if}
                </div>
                {#if user.active_project}
                  <div class="text-xs text-muted ml-8">
                    working on
                    {#if user.active_project.repo_url}
                      <a
                        href={user.active_project.repo_url}
                        target="_blank"
                        class="text-accent hover:text-cyan transition-colors"
                      >
                        {user.active_project.name}
                      </a>
                    {:else}
                      {user.active_project.name}
                    {/if}
                    {#if visualizeGitUrl(user.active_project.repo_url)}
                      <a
                        href={visualizeGitUrl(user.active_project.repo_url)}
                        target="_blank"
                        class="ml-1">🌌</a
                      >
                    {/if}
                  </div>
                {/if}
              </div>
            {/each}
          </div>
        </div>
      {/if}
    {/if}
  </div>
{/if}

<Modal
  bind:open={logoutOpen}
  title="Woah, hold on a sec!"
  description="You sure you want to log out? You can sign back in later but that is a bit of a hassle..."
  maxWidth="max-w-lg"
  hasIcon
  hasActions
>
  {#snippet icon()}
    <svg
      class="h-8 w-8"
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
      aria-hidden="true"
    >
      <path
        fill="currentColor"
        d="M5 21q-.825 0-1.412-.587T3 19v-3q0-.425.288-.712T4 15t.713.288T5 16v3h14V5H5v3q0 .425-.288.713T4 9t-.712-.288T3 8V5q0-.825.588-1.412T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.587 1.413T19 21zm6.65-8H4q-.425 0-.712-.288T3 12t.288-.712T4 11h7.65L9.8 9.15q-.3-.3-.288-.7t.288-.7q.3-.3.713-.312t.712.287L14.8 11.3q.15.15.213.325t.062.375t-.062.375t-.213.325l-3.575 3.575q-.3.3-.712.288T9.8 16.25q-.275-.3-.288-.7t.288-.7z"
      />
    </svg>
  {/snippet}

  {#snippet actions()}
    <div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
      <Button
        type="button"
        onclick={closeLogout}
        variant="dark"
        class="h-10 w-full border border-surface-300 text-muted">Go back</Button
      >

      <form method="post" action={layout.signout_path} class="m-0">
        <input
          type="hidden"
          name="authenticity_token"
          value={layout.csrf_token}
        />
        <input type="hidden" name="_method" value="delete" />
        <Button
          type="submit"
          variant="primary"
          class="h-10 w-full text-on-primary">Log out now</Button
        >
      </form>
    </div>
  {/snippet}
</Modal>

<style>
  :global(#app) {
    display: flex;
    flex: 1 1 auto;
    min-height: 100vh;
    width: 100%;
  }
</style>
