// @vitest-environment happy-dom
//
// Which workspace tabs survive the MenuBar filter, with the bootstrap case as
// the point: an owner logged into a server that has NO projects yet.
//
// That state used to render an empty menu bar. `connected` meant "logged in
// AND a project is active", and both the Administration and Organization gates
// read it as "connected to a server" — so with zero projects only Revision
// Control survived, and the `length <= 1` rule below then hid the tab bar
// outright. Since creating the first project lives in
// Administration -> Server Management, and no CLI verb creates one, a fresh
// server could not be set up through the GUI at all.
//
// Administration and Organization are server-scoped: they gate on `loggedIn`.
import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const state = vi.hoisted(() => ({ connection: {}, settings: {} }));

vi.mock('../context/ConnectionContext', () => ({
  useConnection: () => state.connection,
}));

vi.mock('../context/SettingsContext', () => ({
  useSettings: () => state.settings,
}));

// platform.js pulls in Tauri bridge setup; the bar only needs to know it is
// not on Windows (no frameless window controls in this suite).
vi.mock('../platform', () => ({ isWindows: false, windowControls: null }));

import { MenuBar } from './MenuBar';

let container;
let currentRoot;

/** The owner of a freshly created server: a live session, and no projects. */
function ownerWithNoProjects(overrides = {}) {
  return {
    loggedIn: true,
    projectReady: false,
    orgName: 'Ridgeway',
    account: { role: 'owner' },
    organizationEnabled: true,
    ...overrides,
  };
}

function render(connection, { activeWorkspace = 'revision', ...settings } = {}) {
  state.connection = connection;
  state.settings = { showServerNames: true, showTimeTracking: false, boldTabStyling: false, ...settings };
  act(() => {
    currentRoot = createRoot(container);
    currentRoot.render(
      <MenuBar
        activeWorkspace={activeWorkspace}
        onWorkspaceChange={() => {}}
        visibility={{}}
        onToggleVisible={() => {}}
        onOpenModal={() => {}}
      />
    );
  });
}

/** Visible workspace tab labels, in bar order. */
function tabLabels() {
  return [...container.querySelectorAll('[role="tab"] .menu-tab-label')].map((el) => el.textContent);
}

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
});

afterEach(() => {
  act(() => currentRoot?.unmount());
  currentRoot = null;
  container.remove();
});

describe('workspace tabs on a server with no projects', () => {
  it('shows Administration to an owner who has no project selected', () => {
    render(ownerWithNoProjects());
    expect(tabLabels()).toContain('Administration');
  });

  it('shows Organization when the server has it enabled', () => {
    render(ownerWithNoProjects());
    expect(tabLabels()).toContain('Organization');
  });

  it('does not hide the whole tab bar, since more than one tab survives', () => {
    render(ownerWithNoProjects());
    // The `length <= 1` rule is what turned a partial failure into a total
    // one: with Administration and Organization filtered out, the single
    // surviving Revision Control tab hid the bar and left no hint that
    // anything had been suppressed.
    expect(tabLabels().length).toBeGreaterThan(1);
    expect(tabLabels()).toEqual(['Revision Control', 'Organization', 'Administration']);
  });

  it('still shows Administration to an admin, not just the owner', () => {
    render(ownerWithNoProjects({ account: { role: 'admin' } }));
    expect(tabLabels()).toContain('Administration');
  });

  it('withholds Administration from an ordinary member', () => {
    render(ownerWithNoProjects({ account: { role: 'member' } }));
    expect(tabLabels()).not.toContain('Administration');
  });

  it('withholds Organization when the server has it disabled', () => {
    render(ownerWithNoProjects({ organizationEnabled: false }));
    expect(tabLabels()).not.toContain('Organization');
  });
});

describe('workspace tabs while logged out', () => {
  const loggedOut = {
    loggedIn: false,
    projectReady: false,
    orgName: null,
    account: null,
    organizationEnabled: false,
  };

  it('hides the tab bar entirely', () => {
    render(loggedOut);
    // Only Revision Control would survive, and one tab means no bar.
    expect(tabLabels()).toEqual([]);
  });

  it('marks the connections button offline', () => {
    render(loggedOut);
    expect(container.querySelector('.menu-bar-server-btn--offline')).not.toBeNull();
  });

  it('does not mark it offline for a session with no project', () => {
    render(ownerWithNoProjects());
    // The button shows the org name; an owner on a project-less server is
    // online, whatever the project state.
    expect(container.querySelector('.menu-bar-server-btn--offline')).toBeNull();
  });
});

describe('the Windows menu', () => {
  it('offers the Administration panels with a session but no project', () => {
    render(ownerWithNoProjects(), { activeWorkspace: 'administration' });
    // Each row is a bullet span plus the title, so compare on trimmed text.
    const items = [...container.querySelectorAll('.menu-dropdown-item--window')].map((el) =>
      el.textContent.trim()
    );
    expect(items).toEqual(['Server Management', 'User Management', 'Device Management', 'Console']);
  });

  it('says "Not connected to a server" on Revision Control with no project', () => {
    render(ownerWithNoProjects());
    expect(container.querySelector('.menu-dropdown-item--disabled')?.textContent).toBe(
      'Not connected to a server'
    );
  });
});
