"use client"

import * as React from "react"

import { setLanguage } from "@/app/settings/language"
import { useLocale, useT } from "@/components/locale-provider"
import { cn } from "@/lib/utils"
import { LANGUAGE_NAMES, LOCALES } from "@/lib/i18n"

/**
 * English or Thai, in the sidebar, where somebody who cannot read the screen
 * can find it without reading the screen.
 *
 * Each language is named in itself, never "Thai" in English. The person
 * reaching for this control is by definition the one who cannot read the
 * language it is currently in, so a label they cannot read is a label that does
 * not help them. `ไทย` is findable by shape alone.
 *
 * Two visible choices rather than a menu. A dropdown would hide one of two
 * options behind a press, and its trigger would have to be labelled in one
 * language or the other, which is the problem again.
 *
 * The change is written to the person on the server, so it survives the browser
 * and travels with them to the next terminal. It is not stored here, which is
 * why there is no optimistic state: the button waits, and what comes back is
 * the truth rather than a guess that may not have been saved.
 *
 * **It is drawn twice, on purpose.** routes.json puts the language on
 * `/settings`, which is where anybody who reads the interface will look for it,
 * and the sidebar keeps it because the person who needs it most is the one who
 * cannot read the menu it would otherwise be hidden inside. Two entry points to
 * one control writing one row on one person is not two pieces of state.
 */
export function LanguageSwitch({
  /**
   * Only the colours and the collapse behaviour. The sidebar's own tokens are a
   * shade off inside a card, and the icon-width sidebar hides this whereas a
   * page never should.
   */
  variant = "sidebar",
}: {
  variant?: "sidebar" | "page"
} = {}) {
  const current = useLocale()
  const t = useT()
  const [pending, setPending] = React.useState<string | null>(null)
  const inSidebar = variant === "sidebar"

  return (
    <div
      role="group"
      aria-label={t("nav.language")}
      className={cn(
        "flex",
        inSidebar
          ? "gap-1 px-1 pb-1 group-data-[collapsible=icon]:hidden"
          : "gap-2",
      )}
    >
      {LOCALES.map((locale) => {
        const active = locale === current
        return (
          <button
            key={locale}
            type="button"
            lang={locale}
            /*
              `aria-pressed` and not `disabled` on the active one. A disabled
              button loses focus the moment it becomes disabled, and the focus
              the browser hands back can land on the other language, where one
              stray Enter changes somebody's language without them asking. Both
              stay pressable and a press on the current language does nothing.
            */
            aria-pressed={active}
            disabled={pending !== null}
            onClick={() => {
              if (active) return
              setPending(locale)
              void setLanguage(locale).finally(() => setPending(null))
            }}
            className={cn(
              "rounded-md transition-colors",
              "focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-none",
              inSidebar
                ? "flex-1 px-2 py-1.5 text-sm"
                : "min-w-28 px-4 py-2 text-base",
              inSidebar &&
                (active
                  ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
                  : "text-sidebar-foreground/70 hover:bg-sidebar-accent/60 disabled:opacity-60"),
              !inSidebar &&
                (active
                  ? "bg-accent font-medium text-accent-foreground"
                  : "text-foreground/70 hover:bg-accent/60 disabled:opacity-60"),
            )}
          >
            {LANGUAGE_NAMES[locale]}
          </button>
        )
      })}
    </div>
  )
}
