import { BarChart3, Wand2 } from 'lucide-react';

import { useEffect, useMemo } from 'react';

import { Link, usePage } from '@inertiajs/react';

import { TooltipProvider } from '@/Components/ui/tooltip';
import { getHubNavStructure, type HubKey, type HubNavItem } from '@/config/site-navigation';
import { RUN_NOUNS } from '@/lib/actionLexicon';
import { cn } from '@/lib/utils';
import type { HubReadiness, PageProps, SiteSummary } from '@/types';

import { HubChild } from './HubChild';
import { HubItem } from './HubItem';
import { useSidebar } from './sidebar-context';
import { SidebarSiteSwitcher } from './SidebarSiteSwitcher';

/**
 * NAV-001 V2 — hub-and-spoke sidebar.
 *
 * 5 hubs, each expandable to reveal its children. Day-0 dimming hides the
 * 12 grayed children that the legacy flat sidebar surfaced; clicking a
 * dimmed hub lands on the per-hub explainer page (S3 owns that page).
 *
 * Behaviors:
 *   - Active hub auto-expands on first mount when no saved state exists.
 *   - Explicit toggles persist to localStorage per-user.
 *   - Auto-expansion on navigation does NOT persist.
 *   - Disabled (dimmed) hubs render with a one-line subtext but their
 *     children are not rendered (Day-0 stays clean).
 *   - All children inside an enabled hub render — long-tail per-item
 *     tooltips handle the "GSC connected but no analysis yet" case.
 */

function isUrlInsideHub(url: string, hub: HubNavItem, siteId: string): boolean {
  // Strip query/hash
  const path = url.split(/[?#]/)[0];
  // The hub's own URL counts as inside the hub
  try {
    const hubHref = route(hub.routeName, siteId);
    const hubPath = new URL(hubHref, 'http://placeholder').pathname;
    if (path === hubPath || path.startsWith(hubPath + '/')) return true;
  } catch {
    // Fall through to children
  }
  // Any child URL counts as inside the hub
  for (const child of hub.children) {
    try {
      const childHref = route(child.routeName, siteId);
      const childPath = new URL(childHref, 'http://placeholder').pathname;
      if (path === childPath || path.startsWith(childPath + '/')) return true;
    } catch {
      // Skip route-resolution failures (test envs, missing mocks)
    }
  }
  return false;
}

function isUrlExactlyHub(url: string, hubRoute: string, siteId: string): boolean {
  const path = url.split(/[?#]/)[0];
  try {
    const hubHref = route(hubRoute, siteId);
    const hubPath = new URL(hubHref, 'http://placeholder').pathname;
    return path === hubPath;
  } catch {
    return false;
  }
}

function routeOrFallback(name: string, siteId: string, fallback = '#'): string {
  try {
    return route(name, siteId);
  } catch {
    return fallback;
  }
}

function isUrlExactlyChild(url: string, childRoute: string, siteId: string): boolean {
  const path = url.split(/[?#]/)[0];
  try {
    const childHref = route(childRoute, siteId);
    const childPath = new URL(childHref, 'http://placeholder').pathname;
    return path === childPath || path.startsWith(childPath + '/');
  } catch {
    return false;
  }
}

/**
 * Wave C — persona gating: the shared `plan` Inertia prop is loosely typed as
 * `string`. Narrow it to the plan-tier union (defaulting unknown/absent values
 * to 'free') so `getHubNavStructure` can apply the team/enterprise gate.
 */
function resolvePlanTier(plan: string | undefined): 'free' | 'pro' | 'team' | 'enterprise' {
  return plan === 'pro' || plan === 'team' || plan === 'enterprise' ? plan : 'free';
}

export function SidebarSiteNavV2() {
  const { collapsed, isHubExpanded, toggleHub, autoExpandHub } = useSidebar();
  const { props, url } = usePage<PageProps>();
  const { sites = [], hub_readiness, features } = props;
  // UI-002: Members sub-item gated to team/enterprise plan AND FEATURE_TEAMS flag.
  const plan = resolvePlanTier(props.plan);

  const currentSite = useMemo<SiteSummary | null>(() => {
    if (props.current_site) return props.current_site;
    return null;
  }, [props.current_site]);

  const readiness: HubReadiness | null = hub_readiness ?? null;

  const hubs = useMemo(
    () => (currentSite ? getHubNavStructure(currentSite, readiness, plan, features) : []),
    [currentSite, readiness, plan, features],
  );

  // Determine which hub contains the current URL — drives auto-expand and
  // active-hub styling.
  const activeHubKey = useMemo<HubKey | null>(() => {
    if (!currentSite) return null;
    for (const hub of hubs) {
      if (isUrlInsideHub(url, hub, currentSite.id)) return hub.key;
    }
    return null;
  }, [hubs, url, currentSite]);

  // Auto-expand the active hub on first mount when there's no saved state.
  useEffect(() => {
    if (activeHubKey) {
      autoExpandHub(activeHubKey);
    }
  }, [activeHubKey, autoExpandHub]);

  if (sites.length === 0) return null;

  // Collapsed-rail mode keeps the SiteSwitcher only; the V2 hub structure
  // doesn't make sense in icon-only width. Users can expand the rail to use
  // the new nav.
  if (collapsed) {
    return (
      <div className="border-b border-sidebar-border">
        <div className="px-2 py-2">
          <TooltipProvider delayDuration={0}>
            <SidebarSiteSwitcher
              sites={sites}
              currentSite={currentSite}
              collapsed={collapsed}
            />
          </TooltipProvider>
        </div>
      </div>
    );
  }

  return (
    <div className="border-b border-sidebar-border">
      <div className="px-2 py-2">
        <TooltipProvider delayDuration={0}>
          <SidebarSiteSwitcher
            sites={sites}
            currentSite={currentSite}
            collapsed={collapsed}
          />
        </TooltipProvider>
      </div>
      {currentSite && hubs.length > 0 && (
        <TooltipProvider delayDuration={0}>
          <nav
            aria-label="Site navigation"
            data-testid="sidebar-site-nav-v2"
            className="flex flex-col gap-0.5 px-2 pb-2"
          >
            {hubs.map((hub) => {
              const dimmed = readiness ? !readiness[hub.key] : false;
              const expanded = isHubExpanded(hub.key);
              const isActive = activeHubKey === hub.key;
              let href: string;
              try {
                href = route(hub.routeName, currentSite.id);
              } catch {
                href = '#';
              }
              const isExactHubMatch = isUrlExactlyHub(url, hub.routeName, currentSite.id);
              // Cut 6: actionable Connect-GSC CTA in the dim-state. Today the
              // only gate readiness can flag is GSC; if we add other gates
              // later we can branch on hub.key or extend HubReadiness.
              const dimCta = dimmed
                ? { label: 'Connect GSC', href: routeOrFallback('onboarding.index', currentSite.id) }
                : undefined;
              return (
                <HubItem
                  key={hub.key}
                  hubKey={hub.key}
                  label={hub.label}
                  href={href}
                  Icon={hub.icon}
                  expanded={expanded}
                  isActiveHub={isActive}
                  isExactHubMatch={isExactHubMatch}
                  dimmed={dimmed}
                  dimmedReason={hub.dimmedReason}
                  dimmedCta={dimCta}
                  onToggle={() => toggleHub(hub.key)}
                >
                  {!dimmed &&
                    hub.children.map((child) => {
                      // Show ALL children inside an enabled hub — disabled
                      // ones render with the disabled-tooltip pattern (legacy
                      // behavior). Sidebar consistency across hubs beats the
                      // small ambiguity of disabled-styled siblings; the Cut 3
                      // prune produced empty hubs (Opportunities + Performance
                      // showed 0 children on Day-0) which read as "broken."
                      // The active-state-overrides-disabled rule in HubChild
                      // still ensures "you-are-here" wins over the gate.
                      let childHref: string;
                      try {
                        childHref = route(child.routeName, currentSite.id);
                      } catch {
                        childHref = '#';
                      }
                      const isActiveChild = isUrlExactlyChild(url, child.routeName, currentSite.id);
                      return (
                        <HubChild
                          key={child.key}
                          item={child}
                          href={childHref}
                          isActive={isActiveChild}
                        />
                      );
                    })}
                </HubItem>
              );
            })}
          </nav>
          {/* UI-004: Quick-actions widget — persistent access to the two highest-
              frequency power actions (Recovery Runs + Run Analysis) so the v1 persona
              never needs to dig through hub children to reach them.
              Rendered only when a site is active. Hidden in collapsed-rail mode. */}
          <div
            data-testid="sidebar-quick-actions"
            className="border-t border-sidebar-border px-2 py-2 flex flex-col gap-0.5"
            aria-label="Quick actions"
          >
            <p className="px-2 pb-0.5 text-[10px] font-semibold uppercase tracking-[0.12em] text-sidebar-foreground/40">
              Quick actions
            </p>
            <Link
              href={routeOrFallback('batch-ai.index', currentSite.id)}
              className={cn(
                'flex items-center gap-2 rounded-md px-2 py-1.5 text-xs font-medium text-sidebar-foreground/70',
                'hover:bg-sidebar-accent hover:text-sidebar-foreground transition-colors',
              )}
            >
              <Wand2 className="size-3.5 shrink-0" aria-hidden="true" />
              {RUN_NOUNS.manualRunPage}
            </Link>
            <Link
              href={routeOrFallback('analyze.index', currentSite.id)}
              className={cn(
                'flex items-center gap-2 rounded-md px-2 py-1.5 text-xs font-medium text-sidebar-foreground/70',
                'hover:bg-sidebar-accent hover:text-sidebar-foreground transition-colors',
              )}
            >
              <BarChart3 className="size-3.5 shrink-0" aria-hidden="true" />
              Run Analysis
            </Link>
          </div>
        </TooltipProvider>
      )}
    </div>
  );
}

/**
 * Mobile drawer mirror of SidebarSiteNavV2. Default state on drawer open:
 * all hubs collapsed (per PLAN R3 mobile contract). Tap on hub label closes
 * the drawer and navigates; tap on chevron expands without closing. Both
 * targets are ≥44px tall via `py-2.5`.
 */
export function MobileSidebarSiteNavV2({ onNavigate }: { onNavigate?: () => void }) {
  const { isHubExpanded, toggleHub } = useSidebar();
  const { props, url } = usePage<PageProps>();
  const { sites = [], hub_readiness, features } = props;
  // UI-002: Members sub-item gated to team/enterprise plan AND FEATURE_TEAMS flag.
  const plan = resolvePlanTier(props.plan);

  const currentSite = useMemo<SiteSummary | null>(() => {
    if (props.current_site) return props.current_site;
    return null;
  }, [props.current_site]);

  const readiness: HubReadiness | null = hub_readiness ?? null;

  const hubs = useMemo(
    () => (currentSite ? getHubNavStructure(currentSite, readiness, plan, features) : []),
    [currentSite, readiness, plan, features],
  );

  if (sites.length === 0) return null;

  return (
    <div className="border-b border-sidebar-border pb-2">
      <div className="px-3 py-2">
        <SidebarSiteSwitcher sites={sites} currentSite={currentSite} collapsed={false} />
      </div>
      {currentSite && hubs.length > 0 && (
        <nav
          aria-label="Site navigation"
          data-testid="mobile-sidebar-site-nav-v2"
          className={cn('flex flex-col gap-1 px-3')}
        >
          {hubs.map((hub) => {
            const dimmed = readiness ? !readiness[hub.key] : false;
            const expanded = isHubExpanded(hub.key);
            const href = routeOrFallback(hub.routeName, currentSite.id);
            const isExactHubMatch = isUrlExactlyHub(url, hub.routeName, currentSite.id);
            const dimCta = dimmed
              ? { label: 'Connect GSC', href: routeOrFallback('onboarding.index', currentSite.id) }
              : undefined;
            return (
              <HubItem
                key={hub.key}
                hubKey={hub.key}
                label={hub.label}
                href={href}
                Icon={hub.icon}
                expanded={expanded}
                isActiveHub={isExactHubMatch}
                isExactHubMatch={isExactHubMatch}
                dimmed={dimmed}
                dimmedCta={dimCta}
                dimmedReason={hub.dimmedReason}
                onToggle={() => toggleHub(hub.key)}
                onNavigate={onNavigate}
              >
                {!dimmed &&
                  hub.children.map((child) => {
                    let childHref: string;
                    try {
                      childHref = route(child.routeName, currentSite.id);
                    } catch {
                      childHref = '#';
                    }
                    const isActiveChild = isUrlExactlyChild(url, child.routeName, currentSite.id);
                    return (
                      <HubChild
                        key={child.key}
                        item={child}
                        href={childHref}
                        isActive={isActiveChild}
                        onNavigate={onNavigate}
                      />
                    );
                  })}
              </HubItem>
            );
          })}
        </nav>
      )}
    </div>
  );
}
