<script lang="ts">
  import { Link, router, usePoll } from "@inertiajs/svelte";
  import type { Snippet } from "svelte";
  import { onMount, onDestroy } from "svelte";
  import plur from "plur";

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

  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;
    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(layout.nav.flash.length > 0);
  let flashHiding = $state(false);
  const flashHideDelay = 6000;
  const flashExitDuration = 250;

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

  usePoll(layout.currently_hacking?.interval || 30000, {
    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 countryFlagEmoji = (countryCode?: string | null) => {
    if (!countryCode) return "";
    return countryCode
      .toUpperCase()
      .replace(/./g, (char) =>
        String.fromCodePoint(127397 + char.charCodeAt(0)),
      );
  };

  const streakThemeClasses = (streakDays: number) => {
    if (streakDays >= 30) {
      return {
        bg: "from-blue-900/20 to-indigo-900/20",
        hbg: "hover:from-blue-800/30 hover:to-indigo-800/30",
        bc: "border-blue-700",
        ic: "text-blue-400 group-hover:text-blue-300",
        tc: "text-blue-300 group-hover:text-blue-200",
        tm: "text-blue-400",
      };
    }

    if (streakDays >= 7) {
      return {
        bg: "from-red-900/20 to-orange-900/20",
        hbg: "hover:from-red-800/30 hover:to-orange-800/30",
        bc: "border-red-700",
        ic: "text-red-400 group-hover:text-red-300",
        tc: "text-red-300 group-hover:text-red-200",
        tm: "text-red-400",
      };
    }

    return {
      bg: "from-orange-900/20 to-yellow-900/20",
      hbg: "hover:from-orange-800/30 hover:to-yellow-800/30",
      bc: "border-orange-700",
      ic: "text-orange-400 group-hover:text-orange-300",
      tc: "text-orange-300 group-hover:text-orange-200",
      tm: "text-orange-400",
    };
  };

  const streakLabel = (streakDays: number) => (streakDays > 30 ? "30+" : `${streakDays}`);

  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-500 superadmin-tool";
    if (adminLevel === "admin") return "text-yellow-500 admin-tool";
    if (adminLevel === "viewer") return "text-blue-500 viewer-tool";
    return "";
  };

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

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

  $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-white" : "hover:bg-darkless"}`;
</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
    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>
  <div class="nav-overlay" class:open={navOpen} onclick={closeNav}></div>

  <aside
    class="flex flex-col min-h-screen w-52 bg-dark text-white 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-gray-300"
                  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}
                >
                  {countryFlagEmoji(layout.nav.current_user.country_code)}
                </span>
              {/if}
            </div>

            {#if layout.nav.current_user.streak_days && layout.nav.current_user.streak_days > 0}
              {@const streakTheme = streakThemeClasses(layout.nav.current_user.streak_days)}
              <div
                class={`inline-flex items-center gap-1 px-2 py-1 bg-gradient-to-r ${streakTheme.bg} border ${streakTheme.bc} rounded-lg transition-all duration-200 ${streakTheme.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={`${streakTheme.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 ${streakTheme.tc} transition-colors duration-200`}>
                  {streakLabel(layout.nav.current_user.streak_days)}
                  <span class={`ml-1 font-normal ${streakTheme.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>
          <Link
            href={layout.nav.login_path}
            class="block px-4 py-2 rounded-md transition text-white font-semibold bg-primary hover:bg-secondary text-center"
            >Login</Link
          >
        </div>
      {/if}

      <nav class="space-y-1">
        {#each layout.nav.links as link}
          {#if link.action === "logout"}
            <Link
              href="#"
              type="button"
              onclick={(event) => {
                event.preventDefault();
                openLogout();
              }}
              class={`${navLinkClass(false)} cursor-pointer`}>Logout</Link
            >
          {:else}
            <Link
              href={link.href}
              onclick={handleNavLinkClick}
              class={navLinkClass(link.active)}>{link.label}</Link
            >
          {/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}
              <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-white font-medium"
                  >
                    {link.badge}
                  </span>
                {/if}
              </Link>
            {/each}

            {#each layout.nav.admin_links as link}
              <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-white font-medium"
                  >
                    {link.badge}
                  </span>
                {/if}
              </Link>
            {/each}

            {#each layout.nav.viewer_links as link}
              <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-white font-medium"
                  >
                    {link.badge}
                  </span>
                {/if}
              </Link>
            {/each}

            {#each layout.nav.superadmin_links as link}
              <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>
            {/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 <Link
            href={layout.footer.commit_link}
            class="text-inherit underline opacity-80 hover:opacity-100 transition-opacity duration-200"
            >{layout.footer.git_version}</Link
          >
          from {layout.footer.server_start_time_ago} ago.
          {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})
        </p>
        {#if layout.show_stop_impersonating}
          <Link
            href={layout.stop_impersonating_path}
            data-turbo-prefetch="false"
            class="text-primary font-bold hover:text-red-300 transition-colors duration-200"
            >Stop impersonating</Link
          >
        {/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"
  >
    <div
      class="currently-hacking p-3 bg-dark cursor-pointer select-none flex items-center justify-between"
      onclick={toggleCurrentlyHacking}
    >
      <div class="text-white text-sm font-medium">
        <div class="flex items-center">
          <div
            class="w-2 h-2 rounded-full bg-green-500 animate-pulse mr-2"
          ></div>
          <span class="text-base">{countLabel()}</span>
        </div>
      </div>
    </div>

    {#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}
                    <Link
                      href={`https://hackclub.slack.com/team/${user.slack_uid}`}
                      target="_blank"
                      class="text-blue-500 hover:underline text-sm"
                    >
                      @{user.display_name || `User ${user.id}`}
                    </Link>
                  {:else}
                    <span class="text-white 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}
                      <Link
                        href={user.active_project.repo_url}
                        target="_blank"
                        class="text-accent hover:text-cyan-400 transition-colors"
                      >
                        {user.active_project.name}
                      </Link>
                    {:else}
                      {user.active_project.name}
                    {/if}
                    {#if visualizeGitUrl(user.active_project.repo_url)}
                      <Link
                        href={visualizeGitUrl(user.active_project.repo_url)}
                        target="_blank"
                        class="ml-1">🌌</Link
                      >
                    {/if}
                  </div>
                {/if}
              </div>
            {/each}
          </div>
        </div>
      {/if}
    {/if}
  </div>
{/if}

<div
  class="fixed inset-0 flex items-center justify-center z-9999 transition-opacity duration-300 ease-in-out"
  class:opacity-0={!logoutOpen}
  class:pointer-events-none={!logoutOpen}
  style="background-color: rgba(0, 0, 0, 0.5);backdrop-filter: blur(4px);"
  onclick={(e) => e.target === e.currentTarget && closeLogout()}
>
  <div
    class={`bg-dark border border-primary rounded-lg p-6 max-w-md w-full mx-4 flex flex-col items-center justify-center transform transition-transform duration-300 ease-in-out ${logoutOpen ? "scale-100" : "scale-95"}`}
  >
    <div class="flex flex-col items-center w-full">
      <div class="mb-4 flex justify-center w-full">
        <svg
          class="w-12 h-12 text-primary"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          <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>
      </div>

      <h3 class="text-2xl font-bold text-white mb-2 text-center w-full">
        Woah hold on a sec
      </h3>
      <p class="text-gray-300 mb-6 text-center w-full">
        You sure you want to log out? You can sign back in later but that is a
        bit of a hassle...
      </p>

      <div class="flex w-full gap-3">
        <div class="flex-1 min-w-0">
          <button
            type="button"
            onclick={closeLogout}
            class="w-full h-10 px-4 rounded-lg transition-colors duration-200 cursor-pointer m-0 bg-dark hover:bg-darkless border border-darkless text-gray-300"
            >Go back</button
          >
        </div>
        <div class="flex-1 min-w-0">
          <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"
              class="w-full h-10 px-4 rounded-lg transition-colors duration-200 font-medium cursor-pointer m-0 bg-primary hover:bg-primary/75 text-white"
              >Log out now</button
            >
          </form>
        </div>
      </div>
    </div>
  </div>
</div>

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