import type { Config, Group, WorkApp } from "../types";
import { Back, Cog, Collapse, Forward, Reload } from "./icons";
import { Favicon, GROUP_LABEL, ICON_CHROME } from "./ui";

interface Props {
  config: Config;
  activeId: string | null;
  collapsed: boolean;
  /** How much has arrived in each app since it was last looked at. */
  unread: Record<string, number>;
  onSelect: (id: string) => void;
  onToggleCollapse: () => void;
  onOpenSettings: () => void;
  onToggleGroup: (g: Group) => void;
  onBack: () => void;
  onForward: () => void;
  onReload: () => void;
  /** Height of the title bar the window's content runs underneath. */
  chrome: number;
  /**
   * How wide the collapsed rail has to be for the traffic lights to keep the
   * same margin on their right as macOS gave them on their left. Measured from
   * the buttons themselves, since that inset is macOS's to choose.
   */
  rail: number;
}

const PANEL = 240;

export default function Nav({
  config, activeId, collapsed, unread,
  onSelect, onToggleCollapse, onOpenSettings, onToggleGroup,
  onBack, onForward, onReload, chrome, rail,
}: Props) {
  const groups = [...config.groups].sort((a, b) => a.order - b.order);
  const inGroup = (id: string | null) =>
    config.apps.filter((a) => a.groupId === id).sort((a, b) => a.order - b.order);
  const ungrouped = inGroup(null);
  const disabled = !activeId;

  const shell =
    "flex shrink-0 flex-col overflow-hidden border-r border-slate-200 bg-white " +
    "dark:border-slate-800 dark:bg-slate-900";

  /* Back, forward, reload and settings. Nothing hides an element here — that
     lives on the right-click menu, where you are already pointing at the thing
     you want gone. */
  const controls = (
    <>
      <button onClick={onBack} disabled={disabled} title="Back (or swipe left)" className={ICON_CHROME}>
        <Back />
      </button>
      <button onClick={onForward} disabled={disabled} title="Forward (or swipe right)" className={ICON_CHROME}>
        <Forward />
      </button>
      <button onClick={onReload} disabled={disabled} title="Reload" className={ICON_CHROME}>
        <Reload />
      </button>
    </>
  );

  /* Settings lives at the foot of both layouts: it is the thing you reach for
     least, and putting it there leaves the top for what you use constantly. */
  const settingsButton = (
    <button onClick={onOpenSettings} title="Settings" className={ICON_CHROME}>
      <Cog />
    </button>
  );

  /* A count of what arrived while you were elsewhere. Absent, rather than
     zero, when there is nothing — a row of noughts is just noise. */
  const badge = (id: string, active: boolean) => {
    const n = unread[id] ?? 0;
    if (n === 0) return null;
    return (
      <span
        title={`${n} new since you last looked`}
        className={
          "ml-auto min-w-[18px] shrink-0 rounded-full px-1.5 py-0.5 text-center " +
          "font-mono text-[10px] font-semibold tabular-nums " +
          (active ? "bg-white/25 text-white dark:bg-slate-900/20 dark:text-slate-900" : "bg-sky-500 text-white")
        }
      >
        {n > 99 ? "99+" : n}
      </span>
    );
  };

  // ------------------------------------------------------------ icon rail
  if (collapsed) {
    const railBtn = (app: WorkApp) => {
      const active = app.id === activeId;
      return (
        <button
          key={app.id}
          onClick={() => onSelect(app.id)}
          title={app.name}
          aria-label={app.name}
          className={
            "relative grid size-10 cursor-pointer place-items-center rounded-lg transition-colors " +
            (active
              ? "bg-slate-100 dark:bg-slate-800"
              : "opacity-70 hover:bg-slate-100 hover:opacity-100 dark:hover:bg-slate-800")
          }
        >
          {active && <span className="absolute left-0 h-5 w-[3px] rounded-full bg-sky-500" />}
          <Favicon icon={app.icon} name={app.name} size={20} />
          {(unread[app.id] ?? 0) > 0 && (
            /* A fixed circle, inside the button's own bounds. Padding around a
               number makes a pill as soon as there are two digits, and hanging
               it off the corner puts it under the rail's clip. Anything past
               nine reads as "9+" — the exact figure is in the expanded nav. */
            <span
              title={`${unread[app.id]} new since you last looked`}
              className="absolute right-0 top-0 grid size-[15px] place-items-center
                         rounded-full bg-sky-500 font-mono text-[9px] font-semibold
                         leading-none text-white"
            >
              {unread[app.id] > 9 ? "9+" : unread[app.id]}
            </span>
          )}
        </button>
      );
    };

    return (
      <aside className={`${shell} items-center`} style={{ width: rail }}>
        <div data-tauri-drag-region className="w-full shrink-0" style={{ height: chrome }} />
        {/* Only the expander survives the rail's header. Back and forward are
            a two-finger swipe and reload is ⌘R, so a toolbar here would be
            clutter standing in for something nobody asked for. */}
        <div className="flex w-full flex-col items-center border-b border-slate-200 py-2.5 dark:border-slate-800">
          <button onClick={onToggleCollapse} title="Expand" className={ICON_CHROME}>
            <Collapse open={false} />
          </button>
        </div>
        <nav className="flex min-h-0 flex-1 flex-col items-center gap-1 overflow-y-auto py-3">
          {ungrouped.map(railBtn)}
          {ungrouped.length > 0 && groups.length > 0 && (
            <span className="my-1 h-px w-7 bg-slate-200 dark:bg-slate-800" />
          )}
          {groups.map((g, i) => {
            const apps = inGroup(g.id);
            if (apps.length === 0) return null;
            return (
              <div key={g.id} className="flex flex-col items-center gap-1">
                {i > 0 && <span className="my-1 h-px w-7 bg-slate-200 dark:bg-slate-800" />}
                {apps.map(railBtn)}
              </div>
            );
          })}
        </nav>
        <div className="flex w-full flex-col items-center border-t border-slate-200 py-2 dark:border-slate-800">
          {settingsButton}
        </div>
      </aside>
    );
  }

  // -------------------------------------------------------------- panel
  const row =
    "flex w-full cursor-pointer items-center gap-2 rounded-lg px-2 py-1.5 text-[13px] transition-colors";
  const inactive =
    "text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800";
  const active = "bg-slate-900 text-white dark:bg-white dark:text-slate-900";

  const appRow = (app: WorkApp) => (
    <li key={app.id}>
      <button
        onClick={() => onSelect(app.id)}
        title={app.url}
        className={`${row} ${app.id === activeId ? active : inactive}`}
      >
        <Favicon icon={app.icon} name={app.name} />
        <span className="truncate">{app.name}</span>
        {badge(app.id, app.id === activeId)}
      </button>
    </li>
  );

  return (
    <aside className={shell} style={{ width: PANEL }}>
      <div data-tauri-drag-region className="shrink-0" style={{ height: chrome }} />
      <header className="flex items-center gap-0.5 border-b border-slate-200 px-1.5 py-2.5 dark:border-slate-800">
        {controls}
        <button
          onClick={onToggleCollapse}
          title="Collapse"
          className={`${ICON_CHROME} ml-auto`}
        >
          <Collapse open />
        </button>
      </header>

      <nav className="min-h-0 flex-1 overflow-y-auto px-2 py-3">
        {ungrouped.length > 0 && <ul className="space-y-0.5">{ungrouped.map(appRow)}</ul>}

        {groups.map((g) => {
          const apps = inGroup(g.id);
          return (
            <section key={g.id} className="pt-3 first:pt-0">
              <button
                onClick={() => onToggleGroup(g)}
                className={`${GROUP_LABEL} flex w-full cursor-pointer items-center gap-1 px-2 pb-1
                            hover:text-slate-700 dark:hover:text-slate-200`}
              >
                <svg
                  viewBox="0 0 24 24"
                  className={`size-3 transition-transform ${g.collapsed ? "" : "rotate-90"}`}
                  fill="none" stroke="currentColor" strokeWidth="2.5"
                >
                  <path strokeLinecap="round" strokeLinejoin="round" d="M9 6l6 6-6 6" />
                </svg>
                <span className="truncate">{g.name}</span>
                <span className="ml-auto font-mono text-[10px] opacity-60">{apps.length}</span>
              </button>
              {!g.collapsed && <ul className="space-y-0.5">{apps.map(appRow)}</ul>}
            </section>
          );
        })}

        {config.apps.length === 0 && (
          <p className="px-2 py-3 text-[11px] leading-snug text-slate-500 dark:text-slate-400">
            No apps yet. Open Settings to add the first one.
          </p>
        )}
      </nav>

      <footer className="flex items-center gap-1 border-t border-slate-200 px-1.5 py-2 dark:border-slate-800">
        {settingsButton}
      </footer>
    </aside>
  );
}
