"use client"

import * as React from "react"
import { usePathname, useRouter, useSearchParams } from "next/navigation"

import { useT } from "@/components/locale-provider"
import type { Translate } from "@/lib/i18n"
import type { MessageKey } from "@/lib/i18n/messages"
import { TEAM_TABS, type TeamTab } from "@/lib/team-view"

/**
 * The four tiles across the top: three questions and one measure.
 *
 * The three questions are tabs, and exactly one table is on screen under them.
 * The old screen stacked all three sections down the page, which meant the
 * check queue was below the fold on every day the department had anything
 * behind it, and the thing somebody scrolled past was the thing they came for.
 *
 * The selection is the url. `?tab=waiting` is a link somebody can send, Back
 * returns to the tab they came from, and nothing is mirrored in the browser to
 * go stale. Pushed rather than replaced for exactly that reason.
 *
 * The fourth tile is not a tab and is deliberately outside the tablist: it
 * selects nothing and controls no panel, and a tablist holding a control that
 * does neither is a tablist that lies to a screen reader. It sits in the same
 * grid so the row reads as four, and the grid is defined here rather than on
 * the tiles so the tablist spanning three columns lines up exactly with them.
 */

export type TileCounts = {
  late: number
  today: number
  waiting: number
  /** How many distinct duties the late rows are spread across. */
  lateDuties: number
  /** How many of today's rows are neither finished nor checked. */
  todayOpen: number
  /** How many different people the waiting rows are stuck behind. */
  waitingCheckers: number
}

const LABEL: Record<TeamTab, MessageKey> = {
  late: "team.late",
  today: "team.dueToday",
  waiting: "team.waitingCheck",
}

export function TeamTiles({
  counts,
  completion,
  selected,
}: {
  counts: TileCounts
  /** Null when nothing was due in the window at all. The tile says so. */
  completion: { done: number; due: number } | null
  selected: TeamTab
}) {
  const t = useT()
  const router = useRouter()
  const pathname = usePathname()
  const params = useSearchParams()
  const refs = React.useRef<(HTMLButtonElement | null)[]>([])

  const go = React.useCallback(
    (tab: TeamTab) => {
      const next = new URLSearchParams(params.toString())
      next.set("tab", tab)
      /*
        The person and duty filters travel with the reader. Somebody who has
        narrowed to one name is usually asking about that person across all
        three questions, and a filter silently dropped on every tab press is a
        filter people stop trusting. The count beside the bar, and the Clear
        button, say plainly when a tab is showing less than it holds.

        `sort` and `group` travel too and cost nothing: the other two tabs read
        neither, and coming back to Late finds the ordering the reader left.
      */
      router.push(`${pathname}?${next}`, { scroll: false })
    },
    [params, pathname, router],
  )

  // Arrow keys move and select in one press. Automatic activation is right here
  // because selecting a tab is the whole navigation: there is nothing to
  // confirm, and a reader arrowing along a row of counts wants to see each one.
  const onKeyDown = (event: React.KeyboardEvent) => {
    const at = TEAM_TABS.indexOf(selected)
    const to =
      event.key === "ArrowRight"
        ? (at + 1) % TEAM_TABS.length
        : event.key === "ArrowLeft"
          ? (at - 1 + TEAM_TABS.length) % TEAM_TABS.length
          : event.key === "Home"
            ? 0
            : event.key === "End"
              ? TEAM_TABS.length - 1
              : -1
    if (to < 0) return
    event.preventDefault()
    refs.current[to]?.focus()
    go(TEAM_TABS[to]!)
  }

  return (
    <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
      <div
        role="tablist"
        aria-label={t("team.title")}
        onKeyDown={onKeyDown}
        className="grid gap-3 sm:col-span-2 sm:grid-cols-3 lg:col-span-3"
      >
        {TEAM_TABS.map((tab, index) => (
          <button
            key={tab}
            ref={(node) => {
              refs.current[index] = node
            }}
            type="button"
            role="tab"
            id={`team-tab-${tab}`}
            aria-controls="team-panel"
            aria-selected={tab === selected}
            // One stop in the row, not three. The arrow keys move within it,
            // which is what a tablist owes the keyboard.
            tabIndex={tab === selected ? 0 : -1}
            onClick={() => go(tab)}
            className="flex flex-col gap-1 rounded-xl border bg-card p-4 text-left ring-1 ring-transparent transition-colors outline-none hover:bg-muted/50 focus-visible:ring-3 focus-visible:ring-ring/50 aria-selected:border-foreground/30 aria-selected:bg-muted aria-selected:ring-foreground/10"
          >
            <span className="text-sm text-foreground/70">{t(LABEL[tab])}</span>
            <span
              className={`text-3xl leading-none font-semibold tabular-nums ${
                tab === "late" && counts.late > 0 ? "text-destructive" : ""
              }`}
            >
              {count(counts, tab)}
            </span>
            {/*
              No sub-line under a zero. "across 0 duties" is a sentence about
              nothing, and the tile already says the number is nought.
            */}
            <span className="min-h-5 text-sm text-foreground/70">
              {count(counts, tab) > 0 ? subLine(t, counts, tab) : ""}
            </span>
          </button>
        ))}
      </div>

      <div className="flex flex-col gap-1 rounded-xl border bg-card p-4">
        <span className="text-sm text-foreground/70">
          {t("team.completion")}
        </span>
        {completion ? (
          <>
            <span className="text-3xl leading-none font-semibold tabular-nums">
              {Math.round((completion.done / completion.due) * 100)}%
            </span>
            <span className="min-h-5 text-sm text-foreground/70">
              {t("team.completionDone", completion)}
            </span>
          </>
        ) : (
          /*
            Nothing rather than 0%. A department that was owed nothing in the
            window has not failed at anything, and a red-looking nought over a
            month of holidays is a number somebody acts on.
          */
          <span className="text-sm text-foreground/70">
            {t("team.completionNone")}
          </span>
        )}
      </div>
    </div>
  )
}

function count(counts: TileCounts, tab: TeamTab): number {
  return tab === "late"
    ? counts.late
    : tab === "today"
      ? counts.today
      : counts.waiting
}

/**
 * `{open}` is the only one of the three that reads correctly at one, which is
 * why it is the only one with a single key. "1 duties" and "1 checkers" are
 * wrong in English and there is no plural at all in Thai, so the singular is a
 * second string rather than a rule.
 */
function subLine(t: Translate, counts: TileCounts, tab: TeamTab): string {
  if (tab === "late") {
    return counts.lateDuties === 1
      ? t("team.lateSubOne")
      : t("team.lateSub", { duties: counts.lateDuties })
  }
  if (tab === "today") return t("team.todaySub", { open: counts.todayOpen })
  return counts.waitingCheckers === 1
    ? t("team.waitingSubOne")
    : t("team.waitingSub", { checkers: counts.waitingCheckers })
}
