// @vitest-environment happy-dom
//
// The Repository panel header's "List Changes" shimmer is gated on TWO
// independent things: the user's "List changes hint" appearance setting and
// whether the changelist actually holds anything. Both contexts are mocked
// (same style as modals/ConnectionsModal.test.jsx) so neither a real
// provider nor RepoPanel's file-control hook is needed here.
import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const state = vi.hoisted(() => ({ hasPendingChanges: false, listChangesHint: true }));

vi.mock('../context/FileTreeTabContext', () => ({
  useFileTreeTab: () => ({
    requestListChanges: vi.fn(),
    hasPendingChanges: state.hasPendingChanges,
    historyView: 'list',
    setHistoryView: vi.fn(),
  }),
}));

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

import { RepoHeaderMenus } from './PanelHeaderMenus';

let container;

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
  state.hasPendingChanges = false;
  state.listChangesHint = true;
});

afterEach(() => {
  document.body.removeChild(container);
  container = null;
});

function render() {
  const root = createRoot(container);
  act(() => root.render(<RepoHeaderMenus />));
  return root;
}

const shimmer = () => container.querySelector('.panel-header-shimmer');

describe('RepoHeaderMenus', () => {
  it('shows a List Changes button', () => {
    render();
    const btn = container.querySelector('.panel-header-menu--changes');
    expect(btn.textContent).toContain('List Changes');
  });

  it('does not offer Mirror Server (hidden until it does something)', () => {
    render();
    expect(container.textContent).not.toContain('Mirror Server');
  });

  it('does not shimmer when the changelist is empty', () => {
    state.hasPendingChanges = false;
    render();
    expect(shimmer()).toBeNull();
  });

  it('shimmers when the changelist has something in it', () => {
    state.hasPendingChanges = true;
    render();
    expect(shimmer()).not.toBeNull();
    // The overlay duplicates the label so the gradient has glyphs to clip to.
    expect(shimmer().textContent).toBe('List Changes');
    expect(shimmer().getAttribute('aria-hidden')).toBe('true');
  });

  it('does not shimmer when the List changes hint setting is off', () => {
    state.hasPendingChanges = true;
    state.listChangesHint = false;
    render();
    expect(shimmer()).toBeNull();
  });
});
