'use client';

/**
 * Unified user menu - used by the topbar avatar AND the sidebar-footer
 * profile row. Encapsulates:
 *   - Settings / Notification preferences links
 *   - Dark-mode toggle
 *   - Sign out
 *   - Inline port switcher (when the user has access to >1 port)
 *
 * Everywhere a "click my profile" affordance lives, it should mount this
 * component. That keeps the menu items consistent regardless of which
 * trigger the user reached for.
 */

import { useRouter } from 'next/navigation';
import { useQueryClient } from '@tanstack/react-query';
import { LogOut, Settings, Bell, Check, Building2 } from 'lucide-react';
import { type ReactNode } from 'react';

import { useUIStore } from '@/stores/ui-store';
import { signOut } from '@/lib/auth/client';
import { apiFetch } from '@/lib/api/client';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import type { Port } from '@/lib/db/schema/ports';

interface UserMenuProps {
  /** Element rendered as the dropdown trigger. Must be a single React node
   *  that can receive a click handler (asChild semantics). */
  trigger: ReactNode;
  /** "start" anchors menu under a sidebar-footer trigger (left edge);
   *  "end" anchors under a top-right avatar. Forwarded to Radix. */
  align?: 'start' | 'end';
  user?: { name: string; email: string };
  /** Ports the user has access to. When length > 1, renders a port-switcher
   *  group inside the menu. When ≤ 1, the switcher is omitted. */
  ports?: Port[];
}

export function UserMenu({ trigger, align = 'end', user, ports }: UserMenuProps) {
  const router = useRouter();
  const queryClient = useQueryClient();
  const currentPortId = useUIStore((s) => s.currentPortId);
  const currentPortSlug = useUIStore((s) => s.currentPortSlug);
  const setPort = useUIStore((s) => s.setPort);

  const base = currentPortSlug ? `/${currentPortSlug}` : '';
  const showPortSwitcher = ports && ports.length > 1;

  function handlePortChange(port: Port) {
    if (port.id === currentPortId) return;
    setPort(port.id, port.slug);
    // All cached queries are port-scoped - invalidate so they refetch with
    // the new X-Port-Id header.
    queryClient.invalidateQueries();
    // Remember the choice so the next login lands here automatically.
    // Fire-and-forget - failure shouldn't block the navigation, and any
    // stale value is harmless (the post-login resolver verifies access
    // before honouring it).
    void apiFetch('/api/v1/me', {
      method: 'PATCH',
      body: { preferences: { defaultPortId: port.id } },
    }).catch(() => {
      /* silent - best-effort */
    });
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    router.push(`/${port.slug}/dashboard` as any);
  }

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>
      <DropdownMenuContent align={align} className="w-60">
        <DropdownMenuLabel>
          <div className="font-medium">{user?.name ?? 'My Account'}</div>
          {user?.email && (
            <div className="text-xs text-muted-foreground font-normal">{user.email}</div>
          )}
        </DropdownMenuLabel>
        <DropdownMenuSeparator />

        {showPortSwitcher && (
          <>
            {/* Port list lives in a submenu so the user has to actively hover/
                click "Switch port" to see them - the main menu stays compact
                regardless of how many ports the operator has access to. */}
            <DropdownMenuSub>
              <DropdownMenuSubTrigger>
                <Building2 className="w-4 h-4 mr-2" aria-hidden />
                Switch port
              </DropdownMenuSubTrigger>
              <DropdownMenuSubContent className="w-56">
                {ports!.map((port) => {
                  const active = port.id === currentPortId;
                  return (
                    <DropdownMenuItem
                      key={port.id}
                      onClick={() => handlePortChange(port)}
                      className={active ? 'bg-accent/40' : undefined}
                    >
                      <span className="flex-1 truncate">{port.name}</span>
                      {active && <Check className="ml-2 h-4 w-4 text-brand" aria-hidden />}
                    </DropdownMenuItem>
                  );
                })}
              </DropdownMenuSubContent>
            </DropdownMenuSub>
            <DropdownMenuSeparator />
          </>
        )}

        {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
        <DropdownMenuItem onClick={() => router.push(`${base}/settings` as any)}>
          <Settings className="w-4 h-4 mr-2" aria-hidden />
          Settings
        </DropdownMenuItem>
        <DropdownMenuItem
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          onClick={() => router.push(`${base}/settings#notifications` as any)}
        >
          <Bell className="w-4 h-4 mr-2" aria-hidden />
          Notification preferences
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem
          className="text-destructive focus:text-destructive"
          // `router.push` to /api/auth/sign-out issued a GET against
          // better-auth's POST-only endpoint. Safari (and other browsers
          // serving JSON without a matching renderer) treat that as a
          // file download - the response landed on disk as a `sign_out`
          // file instead of signing the user out. Call the auth client
          // directly to issue a proper POST, then redirect to /login.
          onClick={async () => {
            await signOut();
            router.push('/login');
          }}
        >
          <LogOut className="w-4 h-4 mr-2" aria-hidden />
          Sign Out
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
