/* global React, Icon */
const { useState, useEffect, useRef } = React;

function isCallbackPath(value) {
  return value === '/auth/callback'
    || value.startsWith('/auth/callback?')
    || value === '/workspace/workspace'
    || value.startsWith('/workspace/workspace?');
}

function validateRoutePath(path) {
  const value = String(path || '').trim();
  if (!value) return null;
  const normalized = value.startsWith('/') ? value : `/${value}`;
  if (!isSafeRoutePath(normalized)) return null;
  if (/%[0-9A-Fa-f]{2}/.test(normalized)) {
    let decoded;
    try {
      decoded = decodeURIComponent(normalized);
    } catch {
      return null;
    }
    if (!isSafeRoutePath(decoded)) return null;
    if (isCallbackPath(decoded)) return null;
  }
  if (isCallbackPath(normalized)) return null;
  return normalized;
}

function isSafeRoutePath(path) {
  return /^\/[A-Za-z0-9_\-/?&=.%+]*$/.test(path) &&
    !path.startsWith('//') &&
    !path.startsWith('\\\\') &&
    !path.includes('\\') &&
    !path.includes(':') &&
    !path.includes('#');
}

function normalizeRoutePath(path) {
  const nextPath = String(path || '/dashboard').trim() || '/dashboard';
  return nextPath.startsWith('/') ? nextPath : `/${nextPath}`;
}

function legacyHashRoutePath() {
  if (!window.location.hash || !window.location.hash.startsWith('#/')) return null;
  return validateRoutePath(window.location.hash.slice(1));
}

function getBrowserRoutePath() {
  if (
    window.location.pathname === '/auth/callback'
    || window.location.pathname === '/workspace/workspace'
  ) {
    // Both /auth/callback and the legacy /workspace/workspace are recognized
    // callback URLs. Preserving the search string keeps ?code=... and ?next=...
    // intact for completeAuthCallback. Hash canonicalization runs AFTER auth
    // parsing in api-client.jsx.
    return `${window.location.pathname}${window.location.search || ''}`;
  }
  const legacyPath = legacyHashRoutePath();
  if (legacyPath) {
    window.history.replaceState(null, document.title, legacyPath);
    return legacyPath;
  }
  const pathname = window.location.pathname;
  if (pathname && pathname !== '/') {
    return `${pathname}${window.location.search || ''}`;
  }
  return '/dashboard';
}

function pushBrowserRoute(path) {
  const nextPath = normalizeRoutePath(path);
  window.history.pushState(null, document.title, nextPath);
  window.dispatchEvent(new Event('armature:routechange'));
  return nextPath;
}

function splitRoutePath(path) {
  const normalized = String(path || '/dashboard');
  const queryStart = normalized.indexOf('?');
  if (queryStart === -1) return { pathname: normalized, queryString: '' };
  return {
    pathname: normalized.slice(0, queryStart) || '/dashboard',
    queryString: normalized.slice(queryStart + 1),
  };
}

function useRoute() {
  const [path, setPath] = useState(() => getBrowserRoutePath());
  useEffect(() => {
    const h = () => setPath(getBrowserRoutePath());
    window.addEventListener('armature:routechange', h);
    window.addEventListener('popstate', h);
    return () => {
      window.removeEventListener('armature:routechange', h);
      window.removeEventListener('popstate', h);
    };
  }, []);
  const { pathname, queryString } = splitRoutePath(path);
  const parts = pathname.split('/').filter(Boolean);
  return {
    path: pathname,
    parts,
    queryString,
    navigate: (p, options = {}) => {
      const nextPath = normalizeRoutePath(p);
      if (options?.replace) {
        window.history.replaceState(null, document.title, nextPath);
      } else {
        window.history.pushState(null, document.title, nextPath);
      }
      setPath(nextPath);
    },
  };
}

function getInitials(displayName, email) {
  const src = (displayName || '').trim() || (email || '').split('@')[0] || '';
  if (!src) return 'U';
  const parts = src.replace(/[._-]+/g, ' ').split(/\s+/).filter(Boolean);
  const letters = parts.length >= 2
    ? parts[0][0] + parts[parts.length - 1][0]
    : src.slice(0, 2);
  return letters.toUpperCase();
}

function Sidebar({ activeKey, onNav, me, collapsed, onToggleCollapse, onSignOut }) {
  const [accountMenuOpen, setAccountMenuOpen] = useState(false);
  const accountMenuRef = useRef(null);
  const accountMenuTriggerRef = useRef(null);
  const accountMenuItemRefs = useRef([]);
  // Three divider-separated groups, no section labels. Order is fixed.
  const navGroups = [
    [{ key: 'insights', icon: 'sparkles', label: 'Insights', href: '/insights' }],
    [
      { key: 'workflows', icon: 'workflow', label: 'Workflows', href: '/workflows' },
      { key: 'tool-monitors', icon: 'zap', label: 'Tool monitors', href: '/tool-monitors' },
      { key: 'sources', icon: 'plug', label: 'My MCPs & CLIs', href: '/sources' },
    ],
    [{ key: 'benchmark', icon: 'chart', label: 'Benchmark', href: '/benchmark' }],
  ];
  const accountMenuItems = [
    { key: 'organization', icon: 'settings', label: 'Organization settings', href: '/settings/organization' },
    { key: 'profile', icon: 'user', label: 'Profile', href: '/settings/profile' },
    { key: 'billing', icon: 'creditCard', label: 'Billing', href: '/settings/billing' },
    { key: 'api-keys', icon: 'key', label: 'API keys', href: '/settings/api-keys' },
    { key: 'alerts', icon: 'bell', label: 'Alerts', href: '/settings/alerts' },
    { key: 'invitations', icon: 'mail', label: 'Invite team members', href: '/settings/invitations' },
  ];
  useEffect(() => {
    if (!accountMenuOpen) return undefined;
    const focusFrame = window.requestAnimationFrame(() => {
      accountMenuItemRefs.current[0]?.focus();
    });
    const closeOnOutsideClick = (event) => {
      if (!accountMenuRef.current?.contains(event.target)) {
        setAccountMenuOpen(false);
      }
    };
    const closeOnEscape = (event) => {
      if (event.key === 'Escape') {
        event.preventDefault();
        setAccountMenuOpen(false);
        accountMenuTriggerRef.current?.focus();
      }
    };
    document.addEventListener('mousedown', closeOnOutsideClick);
    document.addEventListener('keydown', closeOnEscape);
    return () => {
      window.cancelAnimationFrame(focusFrame);
      document.removeEventListener('mousedown', closeOnOutsideClick);
      document.removeEventListener('keydown', closeOnEscape);
    };
  }, [accountMenuOpen]);

  function handleAccountMenuKeyDown(event) {
    const items = accountMenuItemRefs.current.filter(Boolean);
    const currentIndex = items.indexOf(document.activeElement);
    if (event.key === 'Tab') {
      setAccountMenuOpen(false);
      return;
    }
    if (event.key === 'Home') {
      event.preventDefault();
      items[0]?.focus();
    } else if (event.key === 'End') {
      event.preventDefault();
      items[items.length - 1]?.focus();
    } else if (event.key === 'ArrowDown') {
      event.preventDefault();
      items[(currentIndex + 1) % items.length]?.focus();
    } else if (event.key === 'ArrowUp') {
      event.preventDefault();
      items[(currentIndex - 1 + items.length) % items.length]?.focus();
    }
  }

  function navigateFromAccountMenu(href) {
    setAccountMenuOpen(false);
    onNav(href);
  }

  return (
    <aside className="sidebar">
      <div
        className="sidebar-brand"
        onClick={collapsed ? onToggleCollapse : undefined}>
        <div className="sidebar-brand-logo">
          <img src="/frontend/assets/armature-app-icon.svg" alt="Armature" />
        </div>
        <div className="sidebar-brand-copy">
          <div className="sidebar-brand-name">Armature</div>
          <div className="sidebar-brand-org">{me?.organization?.name || 'Organization'}</div>
        </div>
        <button
          className="sidebar-brand-toggle"
          onClick={(event) => {
            event.stopPropagation();
            onToggleCollapse();
          }}
          aria-label={collapsed ? 'Open sidebar' : 'Close sidebar'}
          title={collapsed ? 'Open sidebar' : 'Close sidebar'}>
          <Icon name={collapsed ? 'panelExpand' : 'panelCollapse'} size={15} />
        </button>
      </div>
      {navGroups.map((group, groupIdx) => (
        <React.Fragment key={`nav-group-${groupIdx}`}>
          {groupIdx > 0 && <div className="sidebar-divider" role="separator" aria-hidden="true"></div>}
          <nav className="sidebar-nav">
            {group.map((it) => (
              <a key={it.key}
                className={`sidebar-link ${activeKey === it.key ? 'active' : ''}`}
                onClick={(e) => { e.preventDefault(); onNav(it.href); }}
                title={collapsed ? it.label : undefined}
                data-tooltip={it.label}>
                <Icon name={it.icon} className="icon" />
                <span className="label">{it.label}</span>
              </a>
            ))}
          </nav>
        </React.Fragment>
      ))}
      <div className="sidebar-spacer"></div>
      <a
        className={`sidebar-link sidebar-link-floating ${activeKey === 'our-mcp' ? 'active' : ''}`}
        onClick={(e) => { e.preventDefault(); onNav('/armature-mcp'); }}
        href="/armature-mcp"
        title={collapsed ? 'Connect Armature MCP' : undefined}
        data-tooltip="Connect Armature MCP"
        aria-label="Connect Armature MCP">
        <Icon name="mcp" className="icon" />
        <span className="label sidebar-link-logo-label">
          <span>Connect</span>
          <img src="/frontend/assets/armature-icon.svg" alt="Armature" />
          <span>MCP</span>
        </span>
      </a>
      <div className="sidebar-footer" ref={accountMenuRef}>
        <button
          ref={accountMenuTriggerRef}
          className="sidebar-profile-trigger"
          type="button"
          onClick={() => setAccountMenuOpen(open => !open)}
          aria-label="Open account menu"
          aria-haspopup="menu"
          aria-expanded={accountMenuOpen}
          aria-controls={accountMenuOpen ? 'account-menu' : undefined}
          title="Account menu">
          <span className="avatar avatar-menu-trigger" aria-hidden="true">
            <span>{getInitials(me?.profile?.displayName, me?.profile?.email)}</span>
          </span>
          <span className="sidebar-profile-copy">
            <span className="user-name">{me?.profile?.displayName || 'User'}</span>
            <span className="user-email">{me?.profile?.email || ''}</span>
          </span>
          <Icon name="chevronDown" size={12} className="sidebar-profile-caret" />
        </button>
        {accountMenuOpen && (
          <div
            id="account-menu"
            className="avatar-menu"
            role="menu"
            aria-label="Account menu"
            onKeyDown={handleAccountMenuKeyDown}>
            {accountMenuItems.map((item, index) => (
              <button
                key={item.key}
                ref={(node) => { accountMenuItemRefs.current[index] = node; }}
                className="avatar-menu-item"
                type="button"
                role="menuitem"
                autoFocus={index === 0}
                onClick={() => navigateFromAccountMenu(item.href)}>
                <Icon name={item.icon} size={14} />
                <span>{item.label}</span>
              </button>
            ))}
            <div className="avatar-menu-separator" role="separator"></div>
            <button
              ref={(node) => { accountMenuItemRefs.current[accountMenuItems.length] = node; }}
              className="avatar-menu-item"
              type="button"
              role="menuitem"
              onClick={() => {
                setAccountMenuOpen(false);
                onSignOut();
              }}>
              <Icon name="logOut" size={14} />
              <span>Log out</span>
            </button>
          </div>
        )}
      </div>
    </aside>
  );
}

function StatusBadge({ status }) {
  const map = {
    success: { cls: 'badge-success', label: 'Success' },
    partial: { cls: 'badge-warning', label: 'Partial' },
    failed: { cls: 'badge-fail', label: 'Failed' },
    running: { cls: 'badge-running', label: 'Running' },
    pending: { cls: 'badge-pending', label: 'Pending' },
    system_issue: { cls: 'badge-warning', label: 'System issue' },
    canceled: { cls: 'badge-neutral', label: 'Canceled' },
  };
  const m = map[status] || map.pending;
  return <span className={`badge ${m.cls}`}><span className="dot"></span>{m.label}</span>;
}

function displayModelName(name) {
  if (!name) return '';
  return String(name).replace(/^Claude\s+/i, '');
}

function ModelBadge({ id = '', name = '' }) {
  if (!id && !name) return <span className="muted text-xs">—</span>;
  return (
    <span className="badge badge-neutral" style={{ fontFamily: 'var(--font-mono)' }}>
      <span className="dot"></span>
      {displayModelName(name) || id}
    </span>
  );
}

function EmptyState({ icon = 'activity', title, body, action = null }) {
  return (
    <div className="empty">
      <div style={{ width: 44, height: 44, borderRadius: 10, background: 'var(--surface-2)', display: 'inline-grid', placeItems: 'center', color: 'var(--text-3)', marginBottom: 14 }}>
        <Icon name={icon} size={20} />
      </div>
      <h3>{title}</h3>
      {body && <p>{body}</p>}
      {action}
    </div>
  );
}

window.useRoute = useRoute;
window.Sidebar = Sidebar;
window.StatusBadge = StatusBadge;
window.ModelBadge = ModelBadge;
window.displayModelName = displayModelName;
window.EmptyState = EmptyState;
