import { A, useLocation, useNavigate, useSearchParams } from '@solidjs/router';
import {
  For, Show, createEffect, createMemo, createSignal,
  onCleanup, onMount, type JSX,
} from 'solid-js';
import AdminSidebar from './AdminSidebar';
import { isExternalIdentity } from '~/lib/admin-auth';
import { clearAdminSession, hasAdminSession, setAdminSession } from '~/lib/admin-session';
import { Bell, Search, Settings, LogOut, User, ChevronDown } from 'lucide-solid';

// ── Types ────────────────────────────────────────────────────────────────────

type Tab = { href: string; label: string; exact?: boolean };

type SearchResult = { id: string; title: string; subtitle: string; href: string };
type SearchGroup  = { label: string; viewAllHref: string; results: SearchResult[] };

// ── Tab sets ─────────────────────────────────────────────────────────────────

const TAB_SETS: Array<{ prefixes: string[]; tabs: Tab[] }> = [
  {
    prefixes: ['/admin/roles'],
    tabs: [
      { href: '/admin/roles', label: 'Roles', exact: true },
      { href: '/admin/roles/create', label: 'Create Role' },
      { href: '/admin/roles/templates', label: 'View Roles' },
    ],
  },
  {
    prefixes: ['/admin/runtime-roles'],
    tabs: [
      { href: '/admin/runtime-roles', label: 'Roles', exact: true },
      { href: '/admin/runtime-roles/new', label: 'Create Role' },
      { href: '/admin/role-ui-configs', label: 'View Roles' },
    ],
  },
];

// ── Global search ─────────────────────────────────────────────────────────────

const SEARCH_MODULES = [
  {
    label: 'Users',
    viewAllHref: '/admin/users',
    api: '/api/gateway/api/admin/users',
    listKeys: ['users', 'items'],
    titleKeys: ['full_name', 'name'],
    subtitleKeys: ['email', 'phone'],
    detailBase: '/admin/users',
  },
  {
    label: 'Companies',
    viewAllHref: '/admin/company',
    api: '/api/gateway/api/admin/companies',
    listKeys: ['companies', 'items'],
    titleKeys: ['name', 'companyName'],
    subtitleKeys: ['email', 'phone'],
    detailBase: '/admin/company',
  },
  {
    label: 'Employees',
    viewAllHref: '/admin/employees',
    api: '/api/gateway/api/admin/employees',
    listKeys: ['employees', 'items'],
    titleKeys: ['full_name', 'name'],
    subtitleKeys: ['email', 'department_name'],
    detailBase: '/admin/employees',
  },
  {
    label: 'Jobs',
    viewAllHref: '/admin/jobs',
    api: '/api/gateway/api/admin/jobs',
    listKeys: ['jobs', 'items'],
    titleKeys: ['title', 'name'],
    subtitleKeys: ['status', 'company_name'],
    detailBase: '/admin/jobs',
  },
  {
    label: 'Leads',
    viewAllHref: '/admin/leads',
    api: '/api/gateway/api/admin/leads',
    listKeys: ['leads', 'items'],
    titleKeys: ['name', 'full_name'],
    subtitleKeys: ['email', 'status'],
    detailBase: '/admin/leads',
  },
  {
    label: 'Candidates',
    viewAllHref: '/admin/candidate',
    api: '/api/gateway/api/admin/candidates',
    listKeys: ['candidates', 'items'],
    titleKeys: ['full_name', 'name'],
    subtitleKeys: ['email', 'phone'],
    detailBase: '/admin/candidate',
  },
];

function pickStr(obj: Record<string, any>, keys: string[]): string {
  for (const k of keys) if (obj[k]) return String(obj[k]);
  return '—';
}

function extractList(data: any, keys: string[]): any[] {
  if (Array.isArray(data)) return data;
  for (const k of keys) if (Array.isArray(data[k])) return data[k];
  return [];
}

function GlobalSearch() {
  const [query, setQuery]       = createSignal('');
  const [open, setOpen]         = createSignal(false);
  const [groups, setGroups]     = createSignal<SearchGroup[]>([]);
  const [searching, setSearching] = createSignal(false);
  let wrapRef!: HTMLDivElement;
  let timer: ReturnType<typeof setTimeout>;

  const doSearch = async (q: string) => {
    const trimmed = q.trim();
    if (trimmed.length < 2) { setGroups([]); setOpen(false); return; }
    setSearching(true);
    const settled = await Promise.allSettled(
      SEARCH_MODULES.map(async (mod) => {
        const res = await fetch(
          `${mod.api}?search=${encodeURIComponent(trimmed)}&limit=4`,
        ).catch(() => null);
        if (!res?.ok) return null;
        const data = await res.json().catch(() => null);
        if (!data) return null;
        const items = extractList(data, mod.listKeys).slice(0, 4);
        if (!items.length) return null;
        return {
          label: mod.label,
          viewAllHref: mod.viewAllHref,
          results: items.map((item: any) => ({
            id: item.id,
            title: pickStr(item, mod.titleKeys),
            subtitle: pickStr(item, mod.subtitleKeys),
            href: `${mod.detailBase}/${item.id}`,
          })),
        } satisfies SearchGroup;
      }),
    );
    setGroups(settled.flatMap((r) => (r.status === 'fulfilled' && r.value ? [r.value] : [])));
    setOpen(true);
    setSearching(false);
  };

  const handleInput = (val: string) => {
    setQuery(val);
    clearTimeout(timer);
    if (val.trim().length < 2) { setGroups([]); setOpen(false); return; }
    timer = setTimeout(() => doSearch(val), 400);
  };

  const close = () => { setOpen(false); setQuery(''); setGroups([]); };

  const onOutside = (e: MouseEvent) => {
    if (!wrapRef.contains(e.target as Node)) setOpen(false);
  };
  onMount(() => document.addEventListener('mousedown', onOutside));
  onCleanup(() => document.removeEventListener('mousedown', onOutside));

  return (
    <div ref={wrapRef!} class="relative flex-1 max-w-[480px]">
      {/* Search icon */}
      <Search
        size={15}
        class="pointer-events-none absolute left-3.5 top-1/2 -translate-y-1/2 text-gray-400"
      />

      <input
        type="text"
        placeholder="Search for anything..."
        value={query()}
        onInput={(e) => handleInput(e.currentTarget.value)}
        onFocus={() => groups().length > 0 && setOpen(true)}
        onKeyDown={(e) => e.key === 'Escape' && close()}
        class="h-10 w-full rounded-xl border border-gray-200 bg-gray-50 pl-10 pr-4 text-sm text-gray-700 placeholder:text-gray-400 transition-colors focus:border-gray-300 focus:bg-white focus:outline-none"
      />

      {/* Results dropdown */}
      <Show when={open() && groups().length > 0}>
        <div class="absolute left-0 right-0 top-[calc(100%+6px)] z-[200] max-h-[500px] overflow-y-auto rounded-xl border border-gray-200 bg-white shadow-2xl shadow-black/10">
          <For each={groups()}>
            {(group) => (
              <div class="border-b border-gray-100 last:border-0">
                <div class="flex items-center justify-between px-4 pt-3 pb-1.5">
                  <span class="text-[10px] font-black uppercase tracking-widest text-gray-400">
                    {group.label}
                  </span>
                  <A
                    href={group.viewAllHref}
                    onClick={close}
                    class="text-[11px] font-semibold text-orange-500 hover:text-orange-600"
                  >
                    View all →
                  </A>
                </div>
                <For each={group.results}>
                  {(item) => (
                    <A
                      href={item.href}
                      onClick={close}
                      class="flex items-center gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50"
                    >
                      <div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-orange-100 text-sm font-bold text-orange-600">
                        {item.title.trim().slice(0, 1).toUpperCase()}
                      </div>
                      <div class="min-w-0">
                        <p class="truncate text-sm font-semibold text-gray-800">{item.title}</p>
                        <p class="truncate text-xs text-gray-500">{item.subtitle}</p>
                      </div>
                    </A>
                  )}
                </For>
              </div>
            )}
          </For>
        </div>
      </Show>

      {/* No results */}
      <Show when={open() && !searching() && query().trim().length >= 2 && groups().length === 0}>
        <div class="absolute left-0 right-0 top-[calc(100%+6px)] z-[200] rounded-xl border border-gray-200 bg-white px-4 py-6 text-center shadow-2xl shadow-black/10">
          <p class="text-sm text-gray-500">
            No results for "<span class="font-semibold">{query()}</span>"
          </p>
        </div>
      </Show>
    </div>
  );
}

// ── Notification bell ─────────────────────────────────────────────────────────

function NotificationBell(props: { count: number }) {
  const [open, setOpen] = createSignal(false);
  let ref!: HTMLDivElement;

  const onOutside = (e: MouseEvent) => {
    if (!ref.contains(e.target as Node)) setOpen(false);
  };
  onMount(() => document.addEventListener('mousedown', onOutside));
  onCleanup(() => document.removeEventListener('mousedown', onOutside));

  return (
    <div ref={ref!} class="relative">
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        aria-label="Notifications"
        class="relative flex h-9 w-9 items-center justify-center rounded-full text-gray-500 transition-colors hover:bg-gray-100"
      >
        <Bell size={19} />
        <Show when={props.count > 0}>
          <span class="absolute right-1.5 top-1.5 flex h-2.5 w-2.5 items-center justify-center rounded-full bg-orange-500 ring-2 ring-white" />
        </Show>
      </button>

      <Show when={open()}>
        <div class="absolute right-0 top-[calc(100%+6px)] z-[200] w-80 rounded-xl border border-gray-200 bg-white shadow-2xl shadow-black/10">
          <div class="flex items-center justify-between border-b border-gray-100 px-4 py-3">
            <span class="text-[13px] font-bold text-gray-800">Notifications</span>
            <Show when={props.count > 0}>
              <span class="rounded-full bg-orange-100 px-2 py-0.5 text-[11px] font-bold text-orange-600">
                {props.count} new
              </span>
            </Show>
          </div>
          <div class="flex flex-col items-center justify-center py-10 text-center">
            <Bell size={28} class="mb-3 text-gray-300" />
            <p class="text-sm font-medium text-gray-500">Real-time notifications</p>
            <p class="mt-1 text-xs text-gray-400">Connecting to live feed…</p>
          </div>
        </div>
      </Show>
    </div>
  );
}

// ── User menu ─────────────────────────────────────────────────────────────────

function UserMenu(props: { name: string; initials: string; onLogout: () => void }) {
  const [open, setOpen] = createSignal(false);
  let ref!: HTMLDivElement;

  const onOutside = (e: MouseEvent) => {
    if (!ref.contains(e.target as Node)) setOpen(false);
  };
  onMount(() => document.addEventListener('mousedown', onOutside));
  onCleanup(() => document.removeEventListener('mousedown', onOutside));

  return (
    <div ref={ref!} class="relative">
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        class="flex items-center gap-2.5 rounded-lg px-2 py-1.5 transition-colors hover:bg-gray-50"
      >
        <div class="text-right hidden sm:block">
          <p class="text-[13px] font-semibold leading-tight text-gray-800">{props.name}</p>
          <p class="text-[11px] leading-tight text-gray-500">Super Admin</p>
        </div>
        <div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-orange-500 text-sm font-bold text-white">
          {props.initials}
        </div>
      </button>

      <Show when={open()}>
        <div class="absolute right-0 top-[calc(100%+6px)] z-[200] w-48 rounded-xl border border-gray-200 bg-white py-1 shadow-2xl shadow-black/10">
          <A
            href="/admin/profile"
            onClick={() => setOpen(false)}
            class="flex items-center gap-2.5 px-4 py-2.5 text-sm text-gray-700 transition-colors hover:bg-gray-50"
          >
            <User size={15} class="text-gray-400" />
            My Profile
          </A>
          <A
            href="/admin/settings"
            onClick={() => setOpen(false)}
            class="flex items-center gap-2.5 px-4 py-2.5 text-sm text-gray-700 transition-colors hover:bg-gray-50"
          >
            <Settings size={15} class="text-gray-400" />
            Settings
          </A>
          <div class="my-1 border-t border-gray-100" />
          <button
            type="button"
            onClick={() => { setOpen(false); props.onLogout(); }}
            class="flex w-full items-center gap-2.5 px-4 py-2.5 text-sm text-red-600 transition-colors hover:bg-red-50"
          >
            <LogOut size={15} />
            Sign out
          </button>
        </div>
      </Show>
    </div>
  );
}

// ── Tabs ──────────────────────────────────────────────────────────────────────

function ShowTabs(props: {
  tabs: Tab[];
  isTabActive: (tab: Tab) => boolean;
  setTabsTrackEl: (el: HTMLDivElement) => void;
  setTabRefs: (fn: (prev: Record<string, HTMLAnchorElement>) => Record<string, HTMLAnchorElement>) => void;
  tabIndicator: () => { left: number; width: number; ready: boolean };
}) {
  if (props.tabs.length === 0) return null;
  return (
    <div
      ref={props.setTabsTrackEl}
      class="relative mb-6 flex items-center gap-1 border-b border-gray-200"
    >
      <For each={props.tabs}>
        {(tab) => (
          <A
            href={tab.href}
            ref={(el) => props.setTabRefs((prev) => ({ ...prev, [tab.href]: el }))}
            aria-current={props.isTabActive(tab) ? 'page' : undefined}
            class={`px-4 pb-3 pt-3 text-[14px] font-semibold transition-colors ${
              props.isTabActive(tab)
                ? 'text-[#fd6216]'
                : 'text-slate-500 hover:text-slate-800'
            }`}
          >
            {tab.label}
          </A>
        )}
      </For>
      <div
        class={`absolute bottom-0 h-[2px] bg-[#fd6216] transition-all duration-300 ease-out ${
          props.tabIndicator().ready ? 'opacity-100' : 'opacity-0'
        }`}
        style={{ left: `${props.tabIndicator().left}px`, width: `${props.tabIndicator().width}px` }}
      />
    </div>
  );
}

// ── Main shell ────────────────────────────────────────────────────────────────

export default function AdminShell(props: { children: JSX.Element }) {
  const location     = useLocation();
  const navigate     = useNavigate();
  const [searchParams] = useSearchParams();

  const [checkedSession, setCheckedSession] = createSignal(false);
  const [adminName, setAdminName]           = createSignal('Admin User');
  const [sidebarOpen, setSidebarOpen]       = createSignal(false);
  const [sidebarCollapsed, setSidebarCollapsed] = createSignal(false);
  const [notifCount]                        = createSignal(0); // wired in Phase 2 (SSE)

  const [tabsTrackEl, setTabsTrackEl] = createSignal<HTMLDivElement>();
  const [tabRefs, setTabRefs]         = createSignal<Record<string, HTMLAnchorElement>>({});
  const [tabIndicator, setTabIndicator] = createSignal({ left: 0, width: 0, ready: false });

  // ── Tab logic ──────────────────────────────────────────────────────────────
  const tabs = createMemo<Tab[]>(() => {
    const path = location.pathname;
    for (const set of TAB_SETS) {
      if (set.prefixes.some((p) => path === p || path.startsWith(`${p}/`)))
        return set.tabs;
    }
    return [];
  });

  const isTabActive = (tab: Tab) =>
    tab.exact
      ? location.pathname === tab.href
      : location.pathname === tab.href || location.pathname.startsWith(`${tab.href}/`);

  const refreshTabIndicator = () => {
    const activeTab = tabs().find((tab) => isTabActive(tab));
    const track = tabsTrackEl();
    if (!activeTab || !track) { setTabIndicator((p) => ({ ...p, ready: false })); return; }
    const el = tabRefs()[activeTab.href];
    if (!el) return;
    setTabIndicator({ left: el.offsetLeft, width: el.offsetWidth, ready: true });
  };

  createEffect(() => {
    tabs(); location.pathname;
    requestAnimationFrame(refreshTabIndicator);
  });

  onMount(() => {
    window.addEventListener('resize', refreshTabIndicator);
    onCleanup(() => window.removeEventListener('resize', refreshTabIndicator));

    const isLocalDev = typeof window !== 'undefined' &&
      (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');
    const isPreview = searchParams._preview === '1' ||
      (typeof sessionStorage !== 'undefined' &&
        sessionStorage.getItem('nxtgauge_admin_preview') === '1');

    if (isPreview || isLocalDev) {
      if (typeof sessionStorage !== 'undefined')
        sessionStorage.setItem('nxtgauge_admin_preview', '1');
      setAdminSession();
      setCheckedSession(true);
      return;
    }

    const verify = async () => {
      if (!hasAdminSession()) {
        navigate(`/login?from=${encodeURIComponent(location.pathname + location.search)}`, { replace: true });
        return;
      }
      try {
        const accessToken = typeof sessionStorage !== 'undefined'
          ? sessionStorage.getItem('nxtgauge_admin_access_token') || ''
          : '';
        const response = await fetch('/api/gateway/users/auth/me', {
          method: 'GET',
          headers: {
            Accept: 'application/json',
            'x-portal-target': 'admin',
            ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
          },
          credentials: 'include',
        });
        const payload = await response.json().catch(() => ({}));
        if (!response.ok || isExternalIdentity(payload)) throw new Error('Unauthorized');
        if (payload?.full_name) setAdminName(payload.full_name);
        setCheckedSession(true);
      } catch {
        clearAdminSession();
        navigate(`/login?from=${encodeURIComponent(location.pathname + location.search)}`, { replace: true });
      }
    };
    void verify();
  });

  const onLogout = async () => {
    await fetch('/api/gateway/users/auth/logout', {
      method: 'POST',
      headers: { Accept: 'application/json', 'x-portal-target': 'admin' },
      credentials: 'include',
    }).catch(() => {});
    clearAdminSession();
    if (typeof sessionStorage !== 'undefined') {
      sessionStorage.removeItem('nxtgauge_admin_access_token');
      sessionStorage.removeItem('nxtgauge_admin_preview');
    }
    navigate('/login', { replace: true });
  };

  const adminInitials = createMemo(() => {
    const parts = adminName().split(' ').map((s) => s.trim()).filter(Boolean);
    if (parts.length === 0) return 'U';
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
  });

  // Sidebar width — synced between header logo section and sidebar
  const sidebarW = () => (sidebarCollapsed() ? 'w-[72px]' : 'w-64');

  return (
    <div class="min-h-screen bg-white">

      {/* ── Header ── */}
      <header class="fixed inset-x-0 top-0 z-50 flex h-16 w-full items-center border-b border-gray-200 bg-white">

        {/* Logo section — same width as sidebar */}
        <div
          class={`flex shrink-0 items-center justify-center border-r border-gray-200 transition-all duration-300 h-full ${sidebarW()}`}
        >
          <A href="/admin">
            <img
              src="/nxtgauge-icon.png"
              alt="Nxtgauge"
              class="h-8 w-8 object-contain"
            />
          </A>
        </div>

        {/* Search bar */}
        <div class="flex flex-1 items-center px-5">
          <GlobalSearch />
        </div>

        {/* Mobile menu button */}
        <button
          type="button"
          class="mr-4 flex h-9 w-9 items-center justify-center rounded-lg text-gray-500 hover:bg-gray-100 lg:hidden"
          onClick={() => setSidebarOpen((v) => !v)}
          aria-label="Toggle sidebar"
        >
          <svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
            <path stroke-linecap="round" d="M4 7h16M4 12h16M4 17h16" />
          </svg>
        </button>

        {/* Right: Bell + Gear + User */}
        <div class="hidden items-center gap-1 pr-4 lg:flex">
          <NotificationBell count={notifCount()} />

          <A
            href="/admin/settings"
            class="flex h-9 w-9 items-center justify-center rounded-full text-gray-500 transition-colors hover:bg-gray-100"
            aria-label="Settings"
          >
            <Settings size={19} />
          </A>

          <div class="mx-2 h-6 w-px bg-gray-200" />

          <UserMenu
            name={adminName()}
            initials={adminInitials()}
            onLogout={onLogout}
          />
        </div>
      </header>

      {/* ── Body ── */}
      <Show
        when={checkedSession()}
        fallback={
          <div class="fixed inset-0 top-16 flex">
            <div class={`hidden border-r border-gray-200 bg-white lg:block shrink-0 ${sidebarW()}`} />
            <main class="flex flex-1 items-center justify-center bg-gray-50">
              <p class="text-sm text-gray-400">Checking session…</p>
            </main>
          </div>
        }
      >
        <div class="fixed inset-0 top-16 flex">
          {/* Mobile overlay */}
          <div
            class={`absolute inset-0 z-20 bg-black/30 transition-opacity lg:hidden ${
              sidebarOpen()
                ? 'pointer-events-auto opacity-100'
                : 'pointer-events-none opacity-0'
            }`}
            onClick={() => setSidebarOpen(false)}
          />

          {/* Sidebar */}
          <div
            class={`absolute inset-y-0 left-0 z-30 -translate-x-full transition-transform duration-200 lg:static lg:translate-x-0 ${
              sidebarOpen() ? 'translate-x-0' : ''
            }`}
          >
            <AdminSidebar
              collapsed={sidebarCollapsed()}
              onToggle={() => setSidebarCollapsed((v) => !v)}
              onNavigate={() => setSidebarOpen(false)}
              adminName={adminName()}
              adminInitials={adminInitials()}
            />
          </div>

          {/* Main content */}
          <main class="scrollbar min-w-0 flex-1 overflow-y-auto bg-gray-50 p-6">
            <ShowTabs
              tabs={tabs()}
              isTabActive={isTabActive}
              setTabsTrackEl={setTabsTrackEl}
              setTabRefs={setTabRefs}
              tabIndicator={tabIndicator}
            />
            {props.children}
          </main>
        </div>
      </Show>
    </div>
  );
}
