"use client";

import Link from "next/link";
import { useRef, useState, type KeyboardEvent, type ReactNode } from "react";

import styles from "./Worlds.module.css";

export type World = {
  id: string;
  code: string;
  brandName: string;
  name: string;
  unit: string[];
  oneLiner: string;
  href: string;
  /** Caffe: the one world on the system's surface. */
  night: boolean;
};

export type WorldsStrings = {
  aria: string;
  open: string;
  label: string;
  statement: string;
};

/**
 * THE FOUR WORLDS — one stage.
 *
 * Nexys is four kinds of business day, and the way to feel that is not four
 * equal rows but one place where the day changes. The four products stand as
 * an index beside a stage; the stage shows the selected product's own
 * document — the ledger, the delivery note, the payslip, the table map —
 * drawn from its real structure and posting in its own tempo. Choosing
 * another product remounts the stage, so the new document posts in front of
 * the reader, and Caffe turns the stage navy: the one product that runs at
 * night, on a touch screen, in a room.
 *
 * The index is a tablist whose tabs are links. With no script, each tab is
 * simply the way into that product's page, and the first world is shown.
 * The documents themselves are rendered on the server (they need the content
 * loaders) and arrive here as `frames`; this component only decides which
 * one is on the stage.
 */
export function Worlds({
  worlds,
  frames,
  strings,
}: {
  worlds: World[];
  frames: ReactNode[];
  strings: WorldsStrings;
}) {
  const [active, setActive] = useState(0);
  const tabs = useRef<(HTMLAnchorElement | null)[]>([]);
  const current = worlds[active];

  function focusTab(index: number) {
    const next = (index + worlds.length) % worlds.length;
    setActive(next);
    tabs.current[next]?.focus();
  }

  function onKeyDown(event: KeyboardEvent<HTMLAnchorElement>, index: number) {
    switch (event.key) {
      case "ArrowDown":
      case "ArrowRight":
        event.preventDefault();
        focusTab(index + 1);
        break;
      case "ArrowUp":
      case "ArrowLeft":
        event.preventDefault();
        focusTab(index - 1);
        break;
      case "Home":
        event.preventDefault();
        focusTab(0);
        break;
      case "End":
        event.preventDefault();
        focusTab(worlds.length - 1);
        break;
      default:
    }
  }

  return (
    <div className={styles.root} data-tone={current.night ? "navy" : "paper"}>
      <div className={styles.index}>
        <p className={styles.label}>{strings.label}</p>
        <p className={styles.statement}>{strings.statement}</p>

        <div className={styles.tabs} role="tablist" aria-label={strings.aria}>
          {worlds.map((world, index) => {
            const selected = index === active;
            return (
              <a
                key={world.id}
                ref={(el) => {
                  tabs.current[index] = el;
                }}
                href={world.href}
                role="tab"
                id={`world-tab-${world.id}`}
                aria-selected={selected}
                aria-controls={`world-${world.id}`}
                tabIndex={selected ? 0 : -1}
                className={styles.tab}
                data-module={world.id}
                data-selected={selected ? "" : undefined}
                onClick={(event) => {
                  event.preventDefault();
                  setActive(index);
                }}
                onKeyDown={(event) => onKeyDown(event, index)}
              >
                <span className={styles.code}>{world.code}</span>
                <span className={styles.brand}>{world.brandName}</span>
                <span className={styles.unit}>{world.unit.join(" · ")}</span>
              </a>
            );
          })}
        </div>
      </div>

      <div
        className={styles.stage}
        role="tabpanel"
        id={`world-${current.id}`}
        aria-labelledby={`world-tab-${current.id}`}
        data-module={current.id}
      >
        <p className={styles.line}>{current.oneLiner}</p>
        {/* Keyed on the world, so a change of world is a fresh mount and the
            document posts again in its own tempo. */}
        <div key={current.id} className={styles.frame}>
          {frames[active]}
        </div>
        <Link href={current.href} className={styles.open}>
          {strings.open}
          <span className={styles.arrow} aria-hidden="true">
            →
          </span>
        </Link>
      </div>
    </div>
  );
}
