'use client';

import { apiFetch } from '@/lib/api';
import {
  ChevronDown,
  CreditCard,
  Download,
  LifeBuoy,
  LogOut,
  ShieldAlert,
  User as UserIcon,
} from 'lucide-react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';

interface MeUser {
  userId: string;
  // All three can be null on a fresh phone-only signup: name not collected,
  // email not entered, phone is the only stable identifier. Anything that
  // dereferences these MUST handle the null case.
  email: string | null;
  name: string | null;
  phone: string | null;
  plan?: 'hobby' | 'pro' | 'team' | 'enterprise';
  isAdmin?: boolean;
}

const PLAN_LABEL: Record<NonNullable<MeUser['plan']>, string> = {
  hobby: 'Hobby',
  pro: 'Pro',
  team: 'Team',
  enterprise: 'Enterprise',
};

/** Pick a deterministic accent for the avatar based on the email. Keeps
 *  the avatar stable across sessions without needing an uploaded image. */
function avatarShade(seed: string): string {
  let hash = 0;
  for (let i = 0; i < seed.length; i += 1) hash = (hash * 31 + seed.charCodeAt(i)) | 0;
  const palette = [
    'bg-indigo-500/30 text-indigo-200',
    'bg-emerald-500/30 text-emerald-200',
    'bg-rose-500/30 text-rose-200',
    'bg-amber-500/30 text-amber-200',
    'bg-sky-500/30 text-sky-200',
    'bg-fuchsia-500/30 text-fuchsia-200',
  ];
  return palette[Math.abs(hash) % palette.length] ?? palette[0]!;
}

export function UserMenu() {
  const router = useRouter();
  const [user, setUser] = useState<MeUser | null>(null);
  const [open, setOpen] = useState(false);
  const wrapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    apiFetch<{ user: MeUser }>('/v1/auth/me')
      .then((r) => setUser(r.user))
      .catch(() => setUser(null));
  }, []);

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

  async function logout() {
    await apiFetch('/v1/auth/logout', { method: 'POST' }).catch(() => undefined);
    router.push('/');
  }

  if (!user) return null;

  // Pick the best identifier we have. Phone-only signups have null email
  // AND null name — used to crash with .charAt(null) here. Fallback chain:
  // name → email → phone → "Account".
  const identifier =
    user.name?.trim() ||
    user.email ||
    user.phone ||
    'Account';
  const label = identifier;
  const initial = identifier.charAt(0).toUpperCase() || '?';
  // Avatar colour is derived from a stable identifier so it doesn't shift
  // across sessions. Fall back to userId so we always have something.
  const shade = avatarShade(user.email || user.phone || user.userId);

  return (
    <div ref={wrapRef} className="relative">
      <button
        type="button"
        aria-label="Account menu"
        aria-expanded={open}
        onClick={() => setOpen((v) => !v)}
        className="flex h-7 items-center gap-1.5 rounded-md pl-1 pr-1.5 text-[12.5px] text-[--color-fg-muted] transition-colors hover:bg-[--color-bg-subtle] hover:text-[--color-fg]"
      >
        <span
          aria-hidden
          className={`mono inline-flex size-5 items-center justify-center rounded-full text-[11px] font-semibold ${shade}`}
        >
          {initial}
        </span>
        <ChevronDown size={13} className="opacity-60" />
      </button>

      {open && (
        <div
          role="menu"
          // Background + border via inline style: Tailwind v4's bracket-arbitrary
          // syntax `bg-[--color-X]` emits invalid CSS (forgets var() wrap), so the
          // dropdown rendered fully transparent. Inline color-mix with explicit
          // var() gives the frosted look — 88% elevated panel + backdrop-blur on
          // top — same pattern as the marketing burger menu.
          className="absolute right-0 top-9 z-50 w-64 overflow-hidden rounded-md border shadow-lg shadow-black/40 backdrop-blur-md"
          style={{
            backgroundColor: 'color-mix(in oklab, var(--color-bg-elevated) 88%, transparent)',
            borderColor: 'var(--color-border)',
          }}
        >
          <div className="border-b border-[--color-border] px-3.5 py-3">
            <div className="flex items-center gap-2.5">
              <span
                aria-hidden
                className={`mono inline-flex size-8 items-center justify-center rounded-full text-[13px] font-semibold ${shade}`}
              >
                {initial}
              </span>
              <div className="min-w-0">
                <div className="truncate text-[12.5px] font-medium text-[--color-fg]">
                  {label}
                </div>
                <div className="mono truncate text-[10.5px] text-[--color-fg-subtle]">
                  {user.email || user.phone || user.userId.slice(0, 8)}
                </div>
              </div>
            </div>
            {user.plan && (
              <div className="mt-2.5 flex items-center justify-between text-[11px]">
                <span className="text-[--color-fg-subtle]">Plan</span>
                <span className="mono rounded-full border border-[--color-border] bg-[--color-bg-subtle] px-2 py-0.5 text-[10.5px] text-[--color-fg]">
                  {PLAN_LABEL[user.plan]}
                </span>
              </div>
            )}
          </div>

          <nav className="py-1">
            <MenuLink href="/settings/profile" icon={UserIcon} label="Profile" onClick={() => setOpen(false)} />
            <MenuLink href="/settings/billing" icon={CreditCard} label="Billing" onClick={() => setOpen(false)} />
            <MenuLink href="/settings/support" icon={LifeBuoy} label="Support" onClick={() => setOpen(false)} />
            <MenuLink href="/settings/account" icon={Download} label="Your data" onClick={() => setOpen(false)} />
            {user.isAdmin && (
              <MenuLink href="/admin" icon={ShieldAlert} label="Admin panel" onClick={() => setOpen(false)} />
            )}
          </nav>

          <div className="border-t border-[--color-border] py-1">
            <button
              type="button"
              role="menuitem"
              onClick={() => {
                setOpen(false);
                void logout();
              }}
              className="flex w-full items-center gap-2 px-3.5 py-1.5 text-left text-[12.5px] text-[--color-fg-muted] transition-colors hover:bg-[--color-bg-subtle] hover:text-[--color-danger]"
            >
              <LogOut size={13} />
              Sign out
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

function MenuLink({
  href,
  icon: Icon,
  label,
  onClick,
}: {
  href: string;
  icon: React.ComponentType<{ size?: number }>;
  label: string;
  onClick: () => void;
}) {
  return (
    <Link
      role="menuitem"
      href={href}
      onClick={onClick}
      className="flex items-center gap-2 px-3.5 py-1.5 text-[12.5px] text-[--color-fg-muted] transition-colors hover:bg-[--color-bg-subtle] hover:text-[--color-fg]"
    >
      <Icon size={13} />
      {label}
    </Link>
  );
}
