import React, { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const mockStore = vi.hoisted(() => {
  const state = {
    messagesPanelMode: 'inline' as 'sidebar' | 'inline' | 'bottom-sheet',
    setMessagesPanelMode: vi.fn((mode: 'sidebar' | 'inline' | 'bottom-sheet') => {
      state.messagesPanelMode = mode;
    }),
  };

  return { state };
});

vi.mock('@renderer/store', () => ({
  useStore: (selector: (state: typeof mockStore.state) => unknown) => selector(mockStore.state),
}));

import { useGraphSidebarVisibility } from '@features/agent-graph/renderer/hooks/useGraphSidebarVisibility';

function HookProbe(): React.JSX.Element {
  const { sidebarVisible, toggleSidebarVisible } = useGraphSidebarVisibility();

  return React.createElement(
    'button',
    {
      type: 'button',
      onClick: toggleSidebarVisible,
      'data-visible': sidebarVisible ? 'true' : 'false',
    },
    sidebarVisible ? 'visible' : 'hidden'
  );
}

describe('useGraphSidebarVisibility', () => {
  beforeEach(() => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    mockStore.state.messagesPanelMode = 'inline';
    mockStore.state.setMessagesPanelMode.mockClear();
    if (typeof window.localStorage.clear === 'function') {
      window.localStorage.clear();
    } else {
      const keysToRemove: string[] = [];
      for (let i = 0; i < window.localStorage.length; i += 1) {
        const key = window.localStorage.key(i);
        if (key) keysToRemove.push(key);
      }
      keysToRemove.forEach((key) => window.localStorage.removeItem(key));
    }
  });

  afterEach(() => {
    document.body.innerHTML = '';
    vi.unstubAllGlobals();
  });

  it('forces sidebar mode on open when the messages panel is not currently in sidebar mode', async () => {
    window.localStorage.setItem('team-graph-sidebar-visible', 'false');
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(React.createElement(HookProbe));
      await Promise.resolve();
    });

    const button = host.querySelector('button');
    expect(button?.getAttribute('data-visible')).toBe('false');

    await act(async () => {
      button?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(mockStore.state.setMessagesPanelMode).toHaveBeenCalledWith('sidebar');
    expect(button?.getAttribute('data-visible')).toBe('true');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('hides the graph sidebar locally without changing the global messages panel mode', async () => {
    mockStore.state.messagesPanelMode = 'sidebar';
    window.localStorage.setItem('team-graph-sidebar-visible', 'true');
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(React.createElement(HookProbe));
      await Promise.resolve();
    });

    const button = host.querySelector('button');
    expect(button?.getAttribute('data-visible')).toBe('true');

    await act(async () => {
      button?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(mockStore.state.setMessagesPanelMode).not.toHaveBeenCalled();
    expect(button?.getAttribute('data-visible')).toBe('false');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });
});
