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

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[] };

const TAB_SETS: Array<{ prefixes: string[]; tabs: Tab[] }> = [
  {
    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' },
    ],
  },
];

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',
  },
];

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), 350);
  };

  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 ml-6 w-[450px] shrink-0">
      <Search size={20} class="pointer-events-none absolute left-5 top-1/2 -translate-y-1/2 text-[#9498ad]" />
      <input
        type="text"
        value={query()}
        placeholder="Search for anything..."
        onInput={(e) => handleInput(e.currentTarget.value)}
        onFocus={() => groups().length > 0 && setOpen(true)}
        onKeyDown={(e) => e.key === 'Escape' && close()}
        class="h-[58px] w-full rounded-2xl border-2 border-transparent bg-[#f4f5f8] pl-[52px] pr-4 text-[16px] text-[#000032] placeholder:text-[rgba(0,0,50,0.4)] outline-none transition-all focus:border-[#e5e7eb] focus:bg-white"
      />

      <Show when={open() && groups().length > 0}>
        <div class="absolute left-0 right-0 top-[calc(100%+8px)] z-[300] max-h-[460px] overflow-y-auto rounded-2xl border border-[#e5e7eb] bg-white shadow-xl">
          <For each={groups()}>
            {(group) => (
              <div class="border-b border-[#f1f2f5] px-4 py-3 last:border-b-0">
                <div class="mb-2 flex items-center justify-between">
                  <span class="text-[10px] font-bold uppercase tracking-[0.12em] text-[#9aa0b9]">{group.label}</span>
                  <A href={group.viewAllHref} onClick={close} class="text-[12px] font-semibold text-[#fa5014]">View all</A>
                </div>
                <div class="space-y-1">
                  <For each={group.results}>
                    {(item) => (
                      <A href={item.href} onClick={close} class="flex items-center gap-3 rounded-xl px-2 py-2 hover:bg-[#f9fafb]">
                        <div class="flex h-8 w-8 items-center justify-center rounded-full bg-[rgba(250,80,20,0.12)] text-[12px] font-bold text-[#fa5014]">
                          {item.title.trim().slice(0, 1).toUpperCase()}
                        </div>
                        <div class="min-w-0">
                          <p class="truncate text-[13px] font-semibold text-[#000032]">{item.title}</p>
                          <p class="truncate text-[12px] text-[rgba(0,0,50,0.55)]">{item.subtitle}</p>
                        </div>
                      </A>
                    )}
                  </For>
                </div>
              </div>
            )}
          </For>
        </div>
      </Show>

      <Show when={open() && !searching() && query().trim().length >= 2 && groups().length === 0}>
        <div class="absolute left-0 right-0 top-[calc(100%+8px)] z-[300] rounded-2xl border border-[#e5e7eb] bg-white px-4 py-6 text-center text-[13px] text-[rgba(0,0,50,0.55)]">
          No results for "{query()}"
        </div>
      </Show>
    </div>
  );
}

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 mt-1 flex items-center gap-1 border-b border-[#e5e7eb]">
      <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-[#fa5014]' : 'text-[rgba(0,0,50,0.6)] hover:text-[#000032]'
            }`}
          >
            {tab.label}
          </A>
        )}
      </For>
      <div
        class={`absolute bottom-0 h-[2px] bg-[#fa5014] 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>
  );
}

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);

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

  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 adminInitials = createMemo(() => {
    if (adminName().trim().toLowerCase() === 'admin user') return 'AD';
    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();
  });

  const figmaShellMode = createMemo(() =>
    location.pathname === '/admin/department' ||
    location.pathname === '/admin/designation',
  );

  return (
    <div class="min-h-screen bg-[#f4f5f7] text-[#000032]">
      <Show
        when={checkedSession()}
        fallback={<div class="flex min-h-screen items-center justify-center text-[14px] text-[rgba(0,0,50,0.55)]">Checking session…</div>}
      >
        <div class="flex min-h-screen">
          <div class={`fixed 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)} />

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

          <div class="flex min-w-0 flex-1 flex-col">
            <header class="h-[101px] border-b border-[#e5e7eb] bg-white shadow-[0px_1px_3px_0px_rgba(0,0,0,0.1),0px_1px_2px_0px_rgba(0,0,0,0.1)]">
              <div class="flex h-full w-full items-center justify-between px-8">
                <GlobalSearch />
                <div class="flex items-center gap-3">
                  <button type="button" class="relative inline-flex h-11 w-11 items-center justify-center rounded-[14px] text-[#000032] hover:bg-[#f9fafb]" aria-label="Notifications">
                    <Bell size={20} />
                    <Show when={notifCount() > 0}>
                      <span class="absolute right-2 top-2 h-2.5 w-2.5 rounded-full border-2 border-white bg-[#fa5014]" />
                    </Show>
                  </button>
                  <button type="button" class="inline-flex h-11 w-11 items-center justify-center rounded-[14px] text-[#000032] hover:bg-[#f9fafb]" aria-label="Settings">
                    <Settings size={20} />
                  </button>
                  <div class="flex items-center gap-3 border-l-2 border-[#e5e7eb] pl-[18px]">
                    <div class="hidden text-right sm:block">
                      <p class="text-[14px] font-semibold leading-5 text-[#000032]">{adminName()}</p>
                      <p class="text-[12px] leading-4 text-[rgba(0,0,50,0.5)]">Super Admin</p>
                    </div>
                    <button type="button" class="inline-flex h-11 w-11 items-center justify-center rounded-[14px] bg-gradient-to-br from-[#fa5014] to-[#ff6b3d] text-[14px] font-bold text-white shadow-[0px_10px_15px_0px_rgba(0,0,0,0.1),0px_4px_6px_0px_rgba(0,0,0,0.1)]">
                      {adminInitials()}
                    </button>
                  </div>
                  <button type="button" class="inline-flex h-11 w-11 items-center justify-center rounded-[14px] text-[#71759a] lg:hidden" onClick={() => setSidebarOpen((v) => !v)}>
                    <User size={20} />
                  </button>
                </div>
              </div>
            </header>

            <div class="min-h-0 flex-1 overflow-y-auto bg-[#F4F5F7]">
              <main class="w-full px-6 pb-7 pt-6">
                {props.children}
              </main>
            </div>
          </div>
        </div>
      </Show>
    </div>
  );
}
