/* global React, Icon, getStoredWorkspaceId, setStoredWorkspaceId, initializeWorkspaceSelection */
const { useEffect, useRef, useState } = React;

const NAV = [
  {section:'Workspace', items:[
    {key:'dashboard', icon:'layoutDashboard', label:'Dashboard'},
    {key:'conversations', icon:'messagesSquare', label:'Conversations'},
    {key:'leads', icon:'userPlus', label:'Leads'},
    {key:'users', icon:'usersRound', label:'Users', roles:['owner','admin']},
  ]},
  {section:'Report', items:[
    {key:'analytics', icon:'chartCombined', label:'Analytics'},
  ]},
  {section:'Setup', items:[
    {key:'playground', icon:'messagesSquare', label:'Playground'},
    {key:'aiBuilder', icon:'bot', label:'AI Builder'},
    {key:'integrations', icon:'workflow', label:'Integrations'},
    {key:'templates', icon:'fileCode', label:'Templates'},
  ]},
  {section:'Account', items:[
    {key:'billing', icon:'creditCard', label:'Billing', roles:['owner']},
  ]},
];

const PLUGINCHATBOT_PRICING_URL = 'https://pluginchatbot.com/pricing';
const SIDEBAR_PLAN_LABELS = {
  trial: 'Free Trial',
  starter: 'Starter',
  growth: 'Growth',
  business: 'Business',
};

function getSidebarSubscriptionView(subscription) {
  if (!subscription) {
    return {
      state: 'unavailable',
      icon: 'info',
      eyebrow: 'Plan status',
      title: 'Plan unavailable',
      detail: 'Refresh to check your subscription.',
      suggestion: '',
      ctaLabel: 'View Plans',
    };
  }

  const planCode = String(subscription.planCode || '').trim().toLowerCase();
  const planName = String(subscription.planName || SIDEBAR_PLAN_LABELS[planCode] || 'Current Plan').trim();
  const hasDaysValue = subscription.daysRemaining !== null
    && subscription.daysRemaining !== undefined
    && String(subscription.daysRemaining).trim() !== '';
  const rawDaysRemaining = hasDaysValue ? Number(subscription.daysRemaining) : Number.NaN;
  const hasRemainingDays = Number.isFinite(rawDaysRemaining) && rawDaysRemaining >= 0;
  const daysRemaining = hasRemainingDays ? Math.max(0, Math.trunc(rawDaysRemaining)) : null;
  const isExpired = subscription.canUseApp === false
    || String(subscription.status || '').trim().toLowerCase() === 'expired'
    || (hasRemainingDays && daysRemaining === 0);

  if (isExpired) {
    return {
      state: 'expired',
      icon: 'clock',
      eyebrow: 'Plan ended',
      title: planName || 'Your plan',
      detail: 'Your plan is over.',
      suggestion: 'Choose a plan to restore account access.',
      ctaLabel: 'Choose a Plan',
    };
  }

  const detail = hasRemainingDays
    ? `${daysRemaining} ${daysRemaining === 1 ? 'day' : 'days'} remaining`
    : 'Access active';

  if (planCode === 'business') {
    return {
      state: 'business',
      icon: 'checkCircle',
      eyebrow: 'Current plan',
      title: planName,
      detail,
      suggestion: '',
      ctaLabel: '',
    };
  }

  const upgradeCopy = {
    trial: 'Upgrade anytime to unlock integrations.',
    starter: 'Upgrade anytime for more capacity.',
    growth: 'Upgrade to Business for the highest limits.',
  };

  const upgradeLabel = {
    trial: 'Upgrade Plan',
    starter: 'View Upgrade Options',
    growth: 'Upgrade to Business',
  };

  if (upgradeCopy[planCode]) {
    return {
      state: planCode === 'trial' ? 'trial' : 'paid',
      icon: planCode === 'trial' ? 'sparkles' : 'creditCard',
      eyebrow: 'Current plan',
      title: planName,
      detail,
      suggestion: upgradeCopy[planCode],
      ctaLabel: upgradeLabel[planCode],
    };
  }

  return {
    state: 'fallback',
    icon: 'info',
    eyebrow: 'Account access',
    title: planName,
    detail,
    suggestion: '',
    ctaLabel: '',
  };
}

function Sidebar({active, onChange, subscription}) {
  const [userRole, setUserRole] = useState('user');
  const [conversationUnread, setConversationUnread] = useState(0);
  const [workspaceId, setWorkspaceId] = useState(() => getStoredWorkspaceId());
  const [botStatusVersion, setBotStatusVersion] = useState(0);
  const [botStatus, setBotStatus] = useState({
    state: 'checking',
    label: 'Checking bot status',
  });

  useEffect(() => {
    let isMounted = true;

    fetch('/api/auth/me', {
      credentials: 'include',
      cache: 'no-store',
      headers: {
        'cache-control': 'no-cache',
      },
    })
      .then(response => response.json())
      .then(data => {
        if (isMounted && data && data.ok && data.user) {
          setUserRole(data.user.role || 'user');
        }
      })
      .catch(() => {});

    return () => {
      isMounted = false;
    };
  }, []);

  useEffect(() => {
    const updateCount = event => setConversationUnread(Number(event.detail?.count || 0));
    window.addEventListener('pluginchatbot:notification-count', updateCount);
    return () => window.removeEventListener('pluginchatbot:notification-count', updateCount);
  }, []);

  useEffect(() => {
    const handleWorkspaceChange = event => {
      setWorkspaceId(event.detail?.workspaceId || getStoredWorkspaceId());
    };
    const handleBotStatusChange = () => {
      setBotStatusVersion(current => current + 1);
    };

    window.addEventListener('pluginchatbot:workspace-changed', handleWorkspaceChange);
    window.addEventListener('pluginchatbot:bot-status-changed', handleBotStatusChange);

    return () => {
      window.removeEventListener('pluginchatbot:workspace-changed', handleWorkspaceChange);
      window.removeEventListener('pluginchatbot:bot-status-changed', handleBotStatusChange);
    };
  }, []);

  useEffect(() => {
    let isMounted = true;

    if (subscription && !subscription.canUseApp) {
      setBotStatus({ state: 'paused', label: 'Account access paused' });
      return () => { isMounted = false; };
    }

    setBotStatus({ state: 'checking', label: 'Checking bot status' });

    const query = workspaceId ? `?workspaceId=${encodeURIComponent(workspaceId)}` : '';
    fetch(`/api/embedded-bots${query}`, {
      credentials: 'include',
      cache: 'no-store',
      headers: {
        'cache-control': 'no-cache',
      },
    })
      .then(async response => {
        const data = await response.json().catch(() => ({}));
        if (!response.ok || !data.ok) {
          throw new Error(data.error || 'Unable to load bot status.');
        }
        return data;
      })
      .then(data => {
        if (!isMounted) return;
        const bots = Array.isArray(data.bots) ? data.bots : [];
        const isLive = bots.some(bot => (
          Boolean(bot?.botId)
          && Boolean(bot?.openaiConfigured)
          && Boolean(bot?.embedCode)
        ));

        setBotStatus(isLive
          ? { state: 'live', label: 'Bot is live' }
          : { state: 'setup', label: 'Complete bot setup' });
      })
      .catch(() => {
        if (isMounted) {
          setBotStatus({ state: 'setup', label: 'Complete bot setup' });
        }
      });

    return () => {
      isMounted = false;
    };
  }, [workspaceId, botStatusVersion, subscription?.canUseApp, subscription?.status]);

  const canShowItem = item => !item.roles || item.roles.includes(userRole);
  const planView = getSidebarSubscriptionView(subscription);

  return (
    <aside className="sb">
      <a className="sb-logo" href="https://pluginchatbot.com" aria-label="Back to PluginChatBot website">
        <img src="./assets/pluginchatbot-logo.svg" width="36" height="36" alt="PluginChatBot"/>
        <span>PluginChatBot</span>
      </a>

      {NAV.map(s=>(
        <div key={s.section}>
          <div className="sb-section">{s.section}</div>
          {s.items.filter(canShowItem).map(it=>(
            <button
              key={it.key}
              className={`sb-item ${active===it.key?'active':''}`}
              onClick={()=>onChange(it.key)}
              data-tour={it.key}
              aria-current={active===it.key ? 'page' : undefined}
            >
              <Icon name={it.icon} size={16}/> {it.label}
              {it.key === 'conversations' && conversationUnread > 0 && <span className="badge">{conversationUnread > 99 ? '99+' : conversationUnread}</span>}
            </button>
          ))}
        </div>
      ))}

      <div className="sb-footer">
        <div className={`sb-plan-card is-${planView.state}`} aria-label={`${planView.title}. ${planView.detail}`}>
          <div className="sb-plan-head">
            <span className="sb-plan-icon" aria-hidden="true">
              <Icon name={planView.icon} size={15}/>
            </span>
            <span className="sb-plan-copy">
              <span className="sb-plan-eyebrow">{planView.eyebrow}</span>
              <strong>{planView.title}</strong>
            </span>
          </div>
          <div className="sb-plan-detail">{planView.detail}</div>
          {planView.suggestion && <p className="sb-plan-suggestion">{planView.suggestion}</p>}
          {planView.ctaLabel && (
            <a className="sb-plan-action" href={PLUGINCHATBOT_PRICING_URL}>
              <span>{planView.ctaLabel}</span>
              <Icon name="arrowRight" size={14}/>
            </a>
          )}
        </div>
        <div className={`sb-status is-${botStatus.state}`}>
          <span className="sb-status-dot" aria-hidden="true" />
          <span>{botStatus.label}</span>
        </div>
      </div>
    </aside>
  );
}

// Searchable app destinations for the top-bar search. Each maps to a view key
// that onNavigate() understands; keywords power fuzzy matching (e.g. "account
// users" -> Users, "invoice" -> Billing).
const APP_SEARCH_DESTINATIONS = [
  { key: 'dashboard', label: 'Dashboard', keywords: 'dashboard home overview' },
  { key: 'conversations', label: 'Conversations', keywords: 'conversations chats messages inbox' },
  { key: 'leads', label: 'Leads', keywords: 'leads contacts captured enquiries' },
  { key: 'users', label: 'Users', keywords: 'users account users team members roles admin invite' },
  { key: 'analytics', label: 'Analytics', keywords: 'analytics reports metrics stats performance insights' },
  { key: 'playground', label: 'Playground', keywords: 'playground test try preview' },
  { key: 'aiBuilder', label: 'AI Builder', keywords: 'ai builder bot training widget customize embed install knowledge base' },
  { key: 'integrations', label: 'Integrations', keywords: 'integrations hubspot whatsapp messenger instagram live chat crm' },
  { key: 'templates', label: 'Templates', keywords: 'templates template' },
  { key: 'billing', label: 'Billing', keywords: 'billing plan subscription payment upgrade invoice pricing' },
];

function Topbar({onNavigate, activeView}) {
  const [user, setUser] = useState(null);
  const [workspaces, setWorkspaces] = useState([]);
  const [selectedWorkspaceId, setSelectedWorkspaceId] = useState(getStoredWorkspaceId());
  const [workspaceOpen, setWorkspaceOpen] = useState(false);
  const [workspaceBusy, setWorkspaceBusy] = useState(false);
  const [workspaceError, setWorkspaceError] = useState('');
  const [wsModal, setWsModal] = useState(null);
  const [profileOpen, setProfileOpen] = useState(false);
  const [notificationOpen, setNotificationOpen] = useState(false);
  const [notifPermission, setNotifPermission] = useState(() => (window.Notification ? Notification.permission : 'denied'));
  const [notifications, setNotifications] = useState([]);
  const [notificationUnread, setNotificationUnread] = useState(0);
  const [searchQuery, setSearchQuery] = useState('');
  const [searchOpen, setSearchOpen] = useState(false);
  const workspaceRef = useRef(null);
  const profileRef = useRef(null);
  const notificationRef = useRef(null);
  const lastBrowserNotificationRef = useRef('');

  useEffect(() => {
    let isMounted = true;

    fetch('/api/auth/me', {
      credentials: 'include',
      cache: 'no-store',
      headers: {
        'cache-control': 'no-cache',
      },
    })
      .then(response => response.json())
      .then(data => {
        if (!isMounted || !data || !data.ok) return;

        const items = Array.isArray(data.workspaces) ? data.workspaces : [];
        const nextWorkspaceId = initializeWorkspaceSelection(items, data.defaultWorkspaceId);

        if (data.user) setUser(data.user);
        setWorkspaces(items);
        setSelectedWorkspaceId(nextWorkspaceId);
      })
      .catch(() => {});

    return () => {
      isMounted = false;
    };
  }, []);

  useEffect(() => {
    const closeMenus = event => {
      if (workspaceRef.current && !workspaceRef.current.contains(event.target)) {
        setWorkspaceOpen(false);
      }

      if (profileRef.current && !profileRef.current.contains(event.target)) {
        setProfileOpen(false);
      }

      if (notificationRef.current && !notificationRef.current.contains(event.target)) {
        setNotificationOpen(false);
      }
    };

    const syncWorkspace = event => {
      setSelectedWorkspaceId(event.detail?.workspaceId || getStoredWorkspaceId());
    };

    document.addEventListener('click', closeMenus);
    window.addEventListener('pluginchatbot:workspace-changed', syncWorkspace);

    return () => {
      document.removeEventListener('click', closeMenus);
      window.removeEventListener('pluginchatbot:workspace-changed', syncWorkspace);
    };
  }, []);

  useEffect(() => {
    if (!selectedWorkspaceId) return undefined;
    let isMounted = true;

    const loadNotifications = async () => {
      try {
        const data = await fetch(`/api/notifications?workspaceId=${encodeURIComponent(selectedWorkspaceId)}&limit=30`, {
          credentials: 'include',
          cache: 'no-store',
        }).then(readWorkspaceResponse);
        if (!isMounted) return;

        const items = Array.isArray(data.notifications) ? data.notifications : [];
        const unread = Number(data.unreadCount || 0);
        setNotifications(items);
        setNotificationUnread(unread);
        window.dispatchEvent(new CustomEvent('pluginchatbot:notification-count', { detail: { count: unread } }));

        const latestUnread = items.find(item => !item.isRead);
        if (
          latestUnread
          && latestUnread.id !== lastBrowserNotificationRef.current
          && window.Notification
          && Notification.permission === 'granted'
        ) {
          lastBrowserNotificationRef.current = latestUnread.id;
          const browserNotification = new Notification(latestUnread.title || 'PluginChatBot update', {
            body: latestUnread.body || 'A conversation needs your attention.',
          });
          browserNotification.onclick = () => {
            window.focus();
            if (latestUnread.conversationId) {
              window.sessionStorage.setItem('pluginchatbot_open_conversation', latestUnread.conversationId);
              onNavigate('conversations');
            }
            browserNotification.close();
          };
        }
      } catch (error) {}
    };

    loadNotifications();
    const timer = window.setInterval(loadNotifications, 8000);
    return () => {
      isMounted = false;
      window.clearInterval(timer);
    };
  }, [selectedWorkspaceId]);

  const markAllNotifications = async () => {
    if (!selectedWorkspaceId) return;
    try {
      await fetch('/api/notifications/read-all', {
        method: 'POST',
        credentials: 'include',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ workspaceId: selectedWorkspaceId }),
      }).then(readWorkspaceResponse);
      setNotifications(current => current.map(item => ({ ...item, isRead: true })));
      setNotificationUnread(0);
      window.dispatchEvent(new CustomEvent('pluginchatbot:notification-count', { detail: { count: 0 } }));
    } catch (error) {}
  };

  const openNotification = async notification => {
    setNotificationOpen(false);
    if (!notification.isRead) {
      try {
        await fetch(`/api/notifications/${encodeURIComponent(notification.id)}/read`, {
          method: 'POST',
          credentials: 'include',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify({ workspaceId: selectedWorkspaceId }),
        }).then(readWorkspaceResponse);
      } catch (error) {}
    }
    if (notification.conversationId) {
      window.sessionStorage.setItem('pluginchatbot_open_conversation', notification.conversationId);
    }
    onNavigate('conversations');
  };

  const enableBrowserNotifications = async () => {
    if (!window.Notification) return;
    const result = await Notification.requestPermission();
    setNotifPermission(result || Notification.permission);
  };

  const searchTerm = searchQuery.trim().toLowerCase();
  const searchResults = searchTerm
    ? APP_SEARCH_DESTINATIONS.filter(dest =>
        `${dest.label} ${dest.keywords}`.toLowerCase().includes(searchTerm))
    : [];

  const goToSearchResult = (dest) => {
    if (!dest) return;
    onNavigate(dest.key);
    setSearchQuery('');
    setSearchOpen(false);
  };

  const selectedWorkspace = workspaces.find(item => item.workspaceId === selectedWorkspaceId) || workspaces[0] || null;
  const userRole = String(user?.role || 'user').toLowerCase();
  const canDeleteSelectedWorkspace = selectedWorkspace
    && workspaces.length > 1
    && !selectedWorkspace.isDefault
    && (userRole === 'owner' || (userRole === 'user' && selectedWorkspace.createdBy === user?.userId));

  const selectWorkspace = workspaceId => {
    setStoredWorkspaceId(workspaceId);
    setSelectedWorkspaceId(workspaceId);
    setWorkspaceOpen(false);
    setWorkspaceError('');
  };

  const createWorkspace = () => {
    setWorkspaceError('');
    setWorkspaceOpen(false);
    setWsModal({ mode: 'create', value: 'New workspace' });
  };

  const renameWorkspace = () => {
    if (!selectedWorkspace) return;
    setWorkspaceError('');
    setWorkspaceOpen(false);
    setWsModal({ mode: 'rename', value: selectedWorkspace.name || 'My workspace' });
  };

  const deleteWorkspace = () => {
    if (!selectedWorkspace) return;
    setWorkspaceError('');
    setWorkspaceOpen(false);
    setWsModal({ mode: 'delete', value: '' });
  };

  const submitWorkspaceModal = async () => {
    if (!wsModal) return;
    const mode = wsModal.mode;
    const safeName = String(wsModal.value || '').trim();

    if ((mode === 'create' || mode === 'rename') && !safeName) {
      setWorkspaceError('Workspace name is required.');
      return;
    }

    setWorkspaceBusy(true);
    setWorkspaceError('');

    try {
      if (mode === 'create') {
        const data = await fetch('/api/workspaces', {
          method: 'POST',
          credentials: 'include',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify({ name: safeName }),
        }).then(readWorkspaceResponse);
        const items = Array.isArray(data.workspaces) ? data.workspaces : [];
        const nextWorkspaceId = data.workspace?.workspaceId || data.defaultWorkspaceId || items[0]?.workspaceId || '';
        setWorkspaces(items);
        selectWorkspace(nextWorkspaceId);
      } else if (mode === 'rename') {
        if (!selectedWorkspace) return;
        const data = await fetch(`/api/workspaces/${encodeURIComponent(selectedWorkspace.workspaceId)}`, {
          method: 'PATCH',
          credentials: 'include',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify({ name: safeName }),
        }).then(readWorkspaceResponse);
        setWorkspaces(Array.isArray(data.workspaces) ? data.workspaces : workspaces);
      } else if (mode === 'delete') {
        if (!selectedWorkspace) return;
        const data = await fetch(`/api/workspaces/${encodeURIComponent(selectedWorkspace.workspaceId)}`, {
          method: 'DELETE',
          credentials: 'include',
        }).then(readWorkspaceResponse);
        const items = Array.isArray(data.workspaces) ? data.workspaces : [];
        const nextWorkspaceId = data.nextWorkspaceId || items[0]?.workspaceId || '';
        setWorkspaces(items);
        selectWorkspace(nextWorkspaceId);
      }
      setWsModal(null);
    } catch (error) {
      setWorkspaceError(error.message || 'Something went wrong. Please try again.');
    } finally {
      setWorkspaceBusy(false);
    }
  };

  const signOut = async () => {
    try {
      await fetch('/api/auth/logout', {
        method: 'POST',
        credentials: 'include',
      });
    } catch (error) {}

    window.location.href = 'https://pluginchatbot.com';
  };

  return (
    <div className="tb">
      <div className="app-workspace-menu" ref={workspaceRef}>
        <button
          type="button"
          className="tb-workspace app-workspace-button"
          onClick={() => setWorkspaceOpen(!workspaceOpen)}
          aria-label="Switch workspace"
          aria-expanded={workspaceOpen}
        >
          <span>{selectedWorkspace?.name || 'My workspace'}</span>
          <Icon name="chevronDown" size={14}/>
        </button>

        {workspaceOpen && (
          <div className="app-workspace-dropdown">
            <div className="app-workspace-label">Workspaces</div>

            <div className="app-workspace-list">
              {workspaces.map(workspace => (
                <button
                  key={workspace.workspaceId}
                  type="button"
                  className={`app-workspace-option ${workspace.workspaceId === selectedWorkspaceId ? 'is-active' : ''}`}
                  onClick={() => selectWorkspace(workspace.workspaceId)}
                >
                  <span>{workspace.name}</span>
                  {workspace.isDefault && <small className="app-workspace-default">Default</small>}
                  {workspace.workspaceId === selectedWorkspaceId && <Icon name="checkCircle" size={13}/>}
                </button>
              ))}
            </div>

            {workspaceError && <div className="app-workspace-error">{workspaceError}</div>}

            <div className="app-workspace-actions">
              <button type="button" onClick={createWorkspace} disabled={workspaceBusy}>Create workspace</button>
              <button type="button" onClick={renameWorkspace} disabled={workspaceBusy || !selectedWorkspace}>Rename current</button>
              <button
                type="button"
                className="is-danger"
                onClick={deleteWorkspace}
                disabled={workspaceBusy || !canDeleteSelectedWorkspace}
              >
                Delete current
              </button>
            </div>
          </div>
        )}
      </div>

      <div className="tb-search">
        <Icon name="search" size={15}/>
        <input
          placeholder="Search pages… (leads, users, billing)"
          value={searchQuery}
          onChange={event => { setSearchQuery(event.target.value); setSearchOpen(true); }}
          onFocus={() => setSearchOpen(true)}
          onBlur={() => setTimeout(() => setSearchOpen(false), 120)}
          onKeyDown={event => {
            if (event.key === 'Enter') { event.preventDefault(); goToSearchResult(searchResults[0]); }
            else if (event.key === 'Escape') { setSearchOpen(false); }
          }}
        />
        {searchOpen && searchTerm && (
          <div className="tb-search-results" role="listbox">
            {searchResults.length ? searchResults.map(result => (
              <button
                key={result.key}
                type="button"
                className="tb-search-result"
                onMouseDown={() => goToSearchResult(result)}
              >
                <Icon name="arrowRight" size={14}/>
                <span>{result.label}</span>
              </button>
            )) : (
              <div className="tb-search-empty">No matching pages</div>
            )}
          </div>
        )}
      </div>

      <div className="tb-actions">
        <button
          className="tb-icon app-tour-trigger"
          type="button"
          onClick={() => window.dispatchEvent(new CustomEvent('pluginchatbot:start-tour', { detail: { view: activeView } }))}
          aria-label="Start page tour"
          title="Start page tour"
        >
          <Icon name="helpCircle" size={17}/>
        </button>

        <button className="btn btn-secondary" onClick={() => onNavigate('aiBuilder')}>
          <Icon name="codeXml" size={14}/>Get embed
        </button>

        <div className="app-notification-menu" ref={notificationRef}>
          <button
            type="button"
            className="tb-icon app-notification-button"
            onClick={() => setNotificationOpen(!notificationOpen)}
            aria-label="Open notifications"
            aria-expanded={notificationOpen}
          >
            <Icon name="bell" size={16}/>
            {notificationUnread > 0 && <span>{notificationUnread > 99 ? '99+' : notificationUnread}</span>}
          </button>

          {notificationOpen && (
            <div className="app-notification-dropdown">
              <div className="app-notification-head">
                <strong>Notifications</strong>
                <button type="button" onClick={markAllNotifications}>Mark all read</button>
              </div>
              {window.Notification && notifPermission === 'default' && (
                <button type="button" className="app-notification-enable" onClick={enableBrowserNotifications}>
                  Enable browser notifications
                </button>
              )}
              <div className="app-notification-list">
                {notifications.length === 0 && <div className="app-notification-empty">No notifications yet.</div>}
                {notifications.map(notification => (
                  <button
                    key={notification.id}
                    type="button"
                    className={`app-notification-item ${notification.isRead ? '' : 'is-unread'}`}
                    onClick={() => openNotification(notification)}
                  >
                    <strong>{notification.title}</strong>
                    <span>{notification.body}</span>
                    <time>{formatNotificationTime(notification.createdAt)}</time>
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>

        <div className="app-profile-menu" ref={profileRef}>
          <button
            type="button"
            className="tb-avatar app-profile-button"
            onClick={() => setProfileOpen(!profileOpen)}
            aria-label="Open profile menu"
            aria-expanded={profileOpen}
          >
            {getInitials(user?.fullName || user?.email)}
          </button>

          {profileOpen && (
            <div className="app-profile-dropdown">
              <div className="app-profile-user">
                <strong>{user?.fullName || 'PluginChatBot User'}</strong>
                <span>{user?.email || ''}</span>
                <span>{userRole}</span>
              </div>

              <a className="app-profile-link" href="https://pluginchatbot.com">
                Back to Website
              </a>

              <button type="button" className="app-profile-signout" onClick={signOut}>
                Log Out
              </button>
            </div>
          )}
        </div>
      </div>

      {wsModal && ReactDOM.createPortal((
        <div className="pc-ws-modal-overlay" onMouseDown={() => !workspaceBusy && setWsModal(null)}>
          <div className="pc-ws-modal" role="dialog" aria-modal="true" onMouseDown={event => event.stopPropagation()}>
            <h3 className="pc-ws-modal-title">
              {wsModal.mode === 'create' ? 'Create workspace' : wsModal.mode === 'rename' ? 'Rename workspace' : 'Delete workspace'}
            </h3>
            {wsModal.mode === 'delete' ? (
              <p className="pc-ws-modal-text">
                Delete <strong>“{selectedWorkspace?.name}”</strong>? This permanently deletes its chatbot templates, leads, and chat logs. This can’t be undone.
              </p>
            ) : (
              <div className="pc-ws-modal-field">
                <label className="pc-ws-modal-label">Workspace name</label>
                <input
                  className="pc-ws-modal-input"
                  autoFocus
                  value={wsModal.value}
                  disabled={workspaceBusy}
                  maxLength={60}
                  placeholder="e.g. Marketing team"
                  onChange={event => setWsModal(current => ({ ...current, value: event.target.value }))}
                  onKeyDown={event => {
                    if (event.key === 'Enter') submitWorkspaceModal();
                    if (event.key === 'Escape') setWsModal(null);
                  }}
                />
              </div>
            )}
            {workspaceError && <div className="pc-ws-modal-error">{workspaceError}</div>}
            <div className="pc-ws-modal-actions">
              <button type="button" className="pc-ws-btn ghost" onClick={() => setWsModal(null)} disabled={workspaceBusy}>Cancel</button>
              <button
                type="button"
                className={`pc-ws-btn ${wsModal.mode === 'delete' ? 'danger' : 'primary'}`}
                onClick={submitWorkspaceModal}
                disabled={workspaceBusy}
              >
                {workspaceBusy ? 'Working…' : wsModal.mode === 'create' ? 'Create workspace' : wsModal.mode === 'rename' ? 'Save changes' : 'Delete'}
              </button>
            </div>
          </div>
        </div>
      ), document.body)}
    </div>
  );
}

function formatNotificationTime(value) {
  // Server timestamps are UTC without a zone suffix; browsers parse that
  // space-separated form as local time, skewing every displayed time by the
  // viewer's UTC offset. Normalize to an explicit UTC instant first.
  const raw = String(value || '').trim();
  const normalized = /[zZ]|[+-]\d{2}:?\d{2}$/.test(raw) ? raw : `${raw.replace(' ', 'T')}Z`;
  const date = new Date(normalized);
  if (Number.isNaN(date.getTime())) return '';
  return date.toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
}

async function readWorkspaceResponse(response) {
  const data = await response.json().catch(() => ({}));

  if (response.status === 401) {
    window.location.href = (['localhost','127.0.0.1'].includes(location.hostname)?'http://localhost:8788':'https://pluginchatbot.com')+'/login.html?redirect=' + encodeURIComponent(window.location.href);
    throw new Error('Authentication required.');
  }

  if (!response.ok || !data.ok) {
    throw new Error(data.error || 'Workspace request failed.');
  }

  return data;
}

function getInitials(value) {
  const text = String(value || '').trim();

  if (!text) {
    return 'U';
  }

  const parts = text.split(/\s+/).filter(Boolean);

  if (parts.length >= 2) {
    return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
  }

  return text.slice(0, 2).toUpperCase();
}

window.Sidebar = Sidebar;
window.Topbar = Topbar;
