'use client';

import { useRouter } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';

import { BookOpenIcon, type BookOpenIconHandle } from './ui/book-open';
import { ChevronsUpDownIcon, type ChevronsUpDownIconHandle } from './ui/chevrons-up-down';
import { GlobeIcon, type GlobeIconHandle } from './ui/globe';
import { LogOutIcon, type LogOutIconHandle } from './ui/log-out';
import { ShieldCheckIcon, type ShieldCheckIconHandle } from './ui/shield-check';

interface UserInfo {
  name: string | null;
  email: string;
  image: string | null;
  legalName: string | null;
}

interface Props {
  user: UserInfo;
  collapsed: boolean;
  isAdmin?: boolean;
  /** Which way the dropdown opens: 'up' (sidebar footer) or 'down' (admin header). */
  placement?: 'up' | 'down';
  /** 'admin' (the admin header) swaps the website row for a dashboard link
   *  and drops the redundant admin row. */
  variant?: 'default' | 'admin';
}

/**
 * Sidebar-anchored user menu. Collapses to a bare avatar when the sidebar
 * is collapsed; expands to avatar + name + email + chevron when open.
 * Dropdown opens upward with a website/docs link and sign-out.
 *
 * why: the user's own email appears only to themselves within their own
 * authenticated sidebar — the same trust boundary as CLAUDE.md §5.1's
 * carve-out for the Settings/Account page.
 *
 * Icon animations are driven from each menu row's hover state via the
 * component handle — hovering anywhere in the row (icon, label, padding)
 * triggers the animation, not just the icon's own 16px surface.
 */
export function UserMenuButton({
  user,
  collapsed,
  isAdmin = false,
  placement = 'up',
  variant = 'default',
}: Props) {
  const router = useRouter();
  const [open, setOpen] = useState(false);
  const [signingOut, setSigningOut] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
  const iconRef = useRef<ChevronsUpDownIconHandle>(null);
  const [hover, setHover] = useState(false);

  const displayName = user.legalName ?? user.name ?? user.email.split('@')[0]!;

  useEffect(() => {
    if (!iconRef.current) return;
    if (hover) iconRef.current.startAnimation();
    else iconRef.current.stopAnimation();
  }, [hover]);

  useEffect(() => {
    if (!open) return;
    function onDown(e: MouseEvent) {
      if (!containerRef.current?.contains(e.target as Node)) setOpen(false);
    }
    function onKey(e: KeyboardEvent) {
      if (e.key === 'Escape') setOpen(false);
    }
    document.addEventListener('mousedown', onDown);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onDown);
      document.removeEventListener('keydown', onKey);
    };
  }, [open]);

  async function signOut() {
    setSigningOut(true);
    try {
      await fetch('/api/v1/auth/sign-out', {
        method: 'POST',
        credentials: 'include',
      });
    } finally {
      window.location.href = '/signin';
    }
  }

  return (
    <div ref={containerRef} className={collapsed ? 'relative' : 'relative min-w-0 flex-1'}>
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        onMouseEnter={() => setHover(true)}
        onMouseLeave={() => setHover(false)}
        onFocus={() => setHover(true)}
        onBlur={() => setHover(false)}
        aria-haspopup="menu"
        aria-expanded={open}
        aria-label={collapsed ? `account menu for ${displayName}` : undefined}
        title={collapsed ? displayName : undefined}
        className={
          collapsed
            ? 'flex size-8 items-center justify-center rounded-md border border-[var(--color-border-subtle)] transition-colors hover:border-[var(--color-border)]'
            : 'flex h-12 w-full items-center gap-2 rounded-md border border-[var(--color-border-subtle)] px-3 text-left transition-colors hover:border-[var(--color-border)]'
        }
      >
        <Avatar user={user} size={collapsed ? 20 : 28} />
        {!collapsed && (
          <>
            <span className="flex min-w-0 flex-1 flex-col leading-tight">
              <span className="truncate text-xs font-medium text-[var(--color-text)]">
                {displayName}
              </span>
              <span className="truncate font-mono text-[10px] text-[var(--color-text-subtle)]">
                {user.email}
              </span>
            </span>
            <span className="pointer-events-none text-[var(--color-text-muted)]">
              <ChevronsUpDownIcon ref={iconRef} size={14} />
            </span>
          </>
        )}
      </button>

      {open && (
        <div
          role="menu"
          className={`absolute left-0 z-50 w-60 overflow-hidden rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] shadow-[var(--shadow-lg)] ${
            placement === 'down' ? 'top-full mt-2' : 'bottom-full mb-2'
          }`}
        >
          <div className="flex items-center gap-3 border-b border-[var(--color-border-subtle)] px-3 py-3">
            <Avatar user={user} size={32} />
            <div className="flex min-w-0 flex-1 flex-col leading-tight">
              <span className="truncate text-sm font-medium text-[var(--color-text)]">
                {displayName}
              </span>
              <span className="truncate font-mono text-[11px] text-[var(--color-text-subtle)]">
                {user.email}
              </span>
            </div>
          </div>
          <ul className="p-1">
            <li>
              {/* In the admin header this row pivots back to the user dashboard —
                  as an ABSOLUTE link, because the admin cockpit lives on
                  admin.briven.tech where a relative /dashboard 404s. Everywhere
                  else it links out to the public website. */}
              {variant === 'admin' ? (
                <MenuRow
                  as="a"
                  href="https://briven.tech/dashboard"
                  onSelect={() => setOpen(false)}
                  icon={GlobeIcon}
                  label="dashboard"
                />
              ) : (
                <MenuRow
                  as="button"
                  onSelect={() => {
                    setOpen(false);
                    router.push('/');
                  }}
                  icon={GlobeIcon}
                  label="website"
                />
              )}
            </li>
            <li>
              <MenuRow
                as="a"
                href="https://docs.briven.tech"
                target="_blank"
                rel="noreferrer"
                onSelect={() => setOpen(false)}
                icon={BookOpenIcon}
                label="docs"
              />
            </li>
            {isAdmin && variant !== 'admin' && (
              <li>
                <MenuRow
                  as="a"
                  href="https://admin.briven.tech"
                  onSelect={() => setOpen(false)}
                  icon={ShieldCheckIcon}
                  label="admin"
                />
              </li>
            )}
            <li>
              <MenuRow
                as="button"
                onSelect={signOut}
                disabled={signingOut}
                icon={LogOutIcon}
                label={signingOut ? 'signing out…' : 'log out'}
                destructive
              />
            </li>
          </ul>
        </div>
      )}
    </div>
  );
}

type IconHandle = GlobeIconHandle | BookOpenIconHandle | LogOutIconHandle | ShieldCheckIconHandle;
type IconComponent = typeof GlobeIcon | typeof BookOpenIcon | typeof LogOutIcon;

interface MenuRowBaseProps {
  onSelect?: () => void;
  icon: IconComponent;
  label: string;
  destructive?: boolean;
  disabled?: boolean;
}
type MenuRowProps =
  | (MenuRowBaseProps & {
      as: 'a';
      href: string;
      target?: string;
      rel?: string;
    })
  | (MenuRowBaseProps & {
      as: 'button';
    });

/**
 * Single dropdown row. Owns the hover state so the icon's animation starts
 * the moment the cursor enters the row (not just the icon's 16px box).
 */
function MenuRow(props: MenuRowProps) {
  const { icon: Icon, label, destructive, onSelect, disabled } = props;
  const ref = useRef<IconHandle>(null);
  const [hover, setHover] = useState(false);

  useEffect(() => {
    if (!ref.current) return;
    if (hover && !disabled) ref.current.startAnimation();
    else ref.current.stopAnimation();
  }, [hover, disabled]);

  const base = `flex w-full items-center gap-3 rounded px-3 py-2 font-mono text-sm transition-colors ${
    destructive
      ? 'text-[var(--color-error)] hover:bg-[var(--color-surface-overlay)]'
      : 'text-[var(--color-text-muted)] hover:bg-[var(--color-surface-overlay)] hover:text-[var(--color-text)]'
  } disabled:opacity-50`;

  const sharedHandlers = {
    onMouseEnter: () => setHover(true),
    onMouseLeave: () => setHover(false),
    onFocus: () => setHover(true),
    onBlur: () => setHover(false),
  };

  const iconNode = (
    <span className="pointer-events-none">
      <Icon ref={ref as never} size={16} />
    </span>
  );

  if (props.as === 'a') {
    return (
      <a
        href={props.href}
        target={props.target}
        rel={props.rel}
        role="menuitem"
        onClick={onSelect}
        className={base}
        {...sharedHandlers}
      >
        {iconNode}
        {label}
      </a>
    );
  }
  return (
    <button
      type="button"
      role="menuitem"
      onClick={onSelect}
      disabled={disabled}
      className={base}
      {...sharedHandlers}
    >
      {iconNode}
      {label}
    </button>
  );
}

function Avatar({ user, size }: { user: UserInfo; size: number }) {
  const initials = getInitials(user.legalName ?? user.name ?? user.email);
  if (user.image) {
    return (
      <img
        src={user.image}
        alt=""
        width={size}
        height={size}
        className="shrink-0 rounded-full object-cover"
        style={{ width: size, height: size }}
      />
    );
  }
  return (
    <span
      aria-hidden
      className="flex shrink-0 items-center justify-center rounded-full bg-[var(--color-primary-subtle)] font-mono text-[var(--color-primary)]"
      style={{ width: size, height: size, fontSize: Math.round(size * 0.42) }}
    >
      {initials}
    </span>
  );
}

function getInitials(source: string): string {
  const cleaned = source.trim();
  if (!cleaned) return '·';
  const parts = cleaned.includes('@') ? [cleaned.split('@')[0]!] : cleaned.split(/\s+/);
  const letters = parts
    .slice(0, 2)
    .map((p) => p[0])
    .filter(Boolean)
    .join('');
  return (letters || cleaned[0] || '·').toUpperCase();
}
