/**
 * The account tile at the top of the sidebar.
 *
 * It used to carry the Piggy mark, which made the pig face mean two things at
 * once: the agent, and your organisation. Piggy is now one mark with one
 * meaning everywhere in the product, so this tile carries a monogram instead —
 * the workspace's initials on the trigger, the signed-in person's on the menu
 * label above their own email. Both sit in the user's chosen accent, because
 * that accent is the one piece of the interface they picked and identity is
 * where they will look for it.
 *
 * The swatch row in the menu is the same `setAccent` the Settings page calls —
 * not a copy of the palette, and not a second place a colour could be defined.
 *
 * PIG is single-workspace today, so this is a switcher with one entry. It is
 * still a menu rather than a label: it is where identity, appearance and
 * sign-out belong, and the shape does not have to change when a second
 * workspace appears.
 */
import { ChevronsUpDown, Check, LogOut, Monitor, Moon, Settings2, Sun } from 'lucide-react';
import { Link } from 'react-router-dom';
import type { ThemeMode } from '@pig/core';
import { getSupabase } from '@/lib/api';
import { useIdentity } from '@/lib/identity';
import { useTheme } from '@/lib/theme';
import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, useSidebar } from './ui/sidebar';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from './ui/dropdown-menu';
import { Label, cn } from './ui';

const WORKSPACE_NAME = 'Prime Intellect Growth';

/**
 * Two letters at most.
 *
 * Three initials in a 32px square is a monogram nobody can read, and a name
 * with one word still has to fill the chip rather than sit in the corner of
 * it. Falls back to the first character of whatever it was given, because an
 * empty chip beside a name reads as a failed avatar load.
 */
function monogram(name: string): string {
  const words = name.trim().split(/\s+/).filter(Boolean);
  if (words.length === 0) return '?';
  if (words.length === 1) return words[0]!.slice(0, 2).toUpperCase();
  return `${words[0]![0]!}${words[1]![0]!}`.toUpperCase();
}

/**
 * The chip both monograms sit in, so they cannot drift apart.
 *
 * Rounded square for an organisation, circle for a person — the convention
 * every product this one sits beside already uses, and the fastest way to say
 * which of the two rows in this menu is your workspace and which is you. Both
 * are decorative: the name they stand for is always printed next to them.
 */
function Monogram({ text, shape }: { text: string; shape: 'workspace' | 'person' }) {
  return (
    <span
      aria-hidden
      className={cn(
        'flex size-8 shrink-0 items-center justify-center bg-accent-subtle',
        'text-xs font-semibold tracking-[0.04em] text-accent-fg',
        shape === 'workspace' ? 'rounded-lg' : 'rounded-full',
      )}
    >
      {text}
    </span>
  );
}

const MODES: { value: ThemeMode; label: string; icon: typeof Sun }[] = [
  { value: 'light', label: 'Light', icon: Sun },
  { value: 'dark', label: 'Dark', icon: Moon },
  { value: 'system', label: 'System', icon: Monitor },
];

export function AccountSwitcher() {
  const identity = useIdentity();
  const { isMobile, setOpenMobile } = useSidebar();
  const { accent, accents, setAccent, mode, setMode, resolved } = useTheme();

  async function signOut() {
    try {
      await getSupabase()?.auth.signOut();
    } finally {
      // Belt and braces, matching Settings: if the provider call fails a
      // reload still lands on sign-in rather than a half-signed-out interface.
      window.location.href = '/';
    }
  }

  return (
    <SidebarMenu>
      <SidebarMenuItem>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <SidebarMenuButton
              size="lg"
              className="data-[state=open]:bg-sidebar-accent"
              aria-label={`${WORKSPACE_NAME} — account and appearance`}
            >
              <Monogram text={monogram(WORKSPACE_NAME)} shape="workspace" />
              <span className="flex min-w-0 flex-1 flex-col text-left leading-tight group-data-[collapsible=icon]:hidden">
                <span className="truncate text-sm font-semibold text-fg">{WORKSPACE_NAME}</span>
                <span className="truncate text-xs font-normal text-muted">{identity.name}</span>
              </span>
              <ChevronsUpDown className="ml-auto size-4 shrink-0 text-muted group-data-[collapsible=icon]:hidden" />
            </SidebarMenuButton>
          </DropdownMenuTrigger>

          <DropdownMenuContent
            className="w-64"
            side={isMobile ? 'bottom' : 'right'}
            align="start"
            sideOffset={8}
          >
            <DropdownMenuLabel className="flex min-w-0 items-center gap-2 py-2">
              <Monogram text={monogram(identity.name)} shape="person" />
              <span className="flex min-w-0 flex-col">
                <span className="truncate text-sm font-semibold">{identity.name}</span>
                <span className="truncate text-xs font-normal text-muted">{identity.email}</span>
              </span>
            </DropdownMenuLabel>

            <DropdownMenuSeparator />

            <DropdownMenuLabel className="pb-1 pt-2">
              <Label>Accent</Label>
            </DropdownMenuLabel>
            <div className="flex flex-wrap gap-1.5 px-2 pb-2">
              {accents.map((option) => (
                <button
                  key={option.key}
                  type="button"
                  onClick={() => setAccent(option.key)}
                  aria-label={option.label}
                  aria-pressed={accent === option.key}
                  title={option.label}
                  className={cn(
                    'grid size-7 place-items-center rounded-full border transition-transform hover:scale-110',
                    accent === option.key ? 'border-fg' : 'border-border',
                  )}
                  // The dark tuning of each accent is a different colour, not a
                  // dimmed one. A swatch showing the light value in dark mode
                  // is a swatch showing a colour the user will not get.
                  style={{
                    background: `hsl(${resolved === 'dark' ? option.dark.accent : option.light.accent})`,
                  }}
                >
                  {accent === option.key ? (
                    <Check className="size-3.5 text-white mix-blend-difference" aria-hidden />
                  ) : null}
                </button>
              ))}
            </div>

            <DropdownMenuSeparator />

            <DropdownMenuLabel className="pb-1 pt-2">
              <Label>Appearance</Label>
            </DropdownMenuLabel>
            {MODES.map((option) => (
              <DropdownMenuItem
                key={option.value}
                className="min-h-11"
                onSelect={() => setMode(option.value)}
              >
                <option.icon aria-hidden />
                {option.label}
                {mode === option.value ? <Check className="ml-auto size-4" aria-hidden /> : null}
              </DropdownMenuItem>
            ))}

            <DropdownMenuSeparator />

            <DropdownMenuItem asChild className="min-h-11">
              <Link to="/settings" onClick={() => setOpenMobile(false)}>
                <Settings2 aria-hidden />
                Settings
              </Link>
            </DropdownMenuItem>
            <DropdownMenuItem className="min-h-11" onSelect={() => void signOut()}>
              <LogOut aria-hidden />
              Sign out
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </SidebarMenuItem>
    </SidebarMenu>
  );
}
