/**
 * TabUI slice unit tests.
 * Tests per-tab UI state isolation (expansion states, context panel, scroll position).
 */

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import { installMockElectronAPI, type MockElectronAPI } from '../../mocks/electronAPI';

import { createTestStore, type TestStore } from './storeTestUtils';

describe('tabUISlice', () => {
  let store: TestStore;
  let _mockAPI: MockElectronAPI;

  beforeEach(() => {
    vi.useFakeTimers();
    _mockAPI = installMockElectronAPI();
    store = createTestStore();

    // Mock crypto.randomUUID for predictable tab IDs
    let uuidCounter = 0;
    vi.stubGlobal('crypto', {
      randomUUID: () => `test-uuid-${++uuidCounter}`,
    });
  });

  afterEach(() => {
    vi.useRealTimers();
    vi.restoreAllMocks();
  });

  describe('initTabUIState', () => {
    it('should initialize UI state for a new tab', () => {
      expect(store.getState().tabUIStates.size).toBe(0);

      store.getState().initTabUIState('tab-1');

      expect(store.getState().tabUIStates.size).toBe(1);
      expect(store.getState().tabUIStates.has('tab-1')).toBe(true);

      const tabState = store.getState().tabUIStates.get('tab-1');
      expect(tabState?.expandedAIGroupIds.size).toBe(0);
      expect(tabState?.expandedDisplayItemIds.size).toBe(0);
      expect(tabState?.expandedSubagentTraceIds.size).toBe(0);
      expect(tabState?.showContextPanel).toBe(false);
      expect(tabState?.savedScrollTop).toBeUndefined();
    });

    it('should not reinitialize existing tab state', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().toggleAIGroupExpansionForTab('tab-1', 'group-1');

      // Try to reinitialize
      store.getState().initTabUIState('tab-1');

      // Should still have the expanded group
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(true);
    });
  });

  describe('cleanupTabUIState', () => {
    it('should remove UI state for a tab', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().initTabUIState('tab-2');
      expect(store.getState().tabUIStates.size).toBe(2);

      store.getState().cleanupTabUIState('tab-1');

      expect(store.getState().tabUIStates.size).toBe(1);
      expect(store.getState().tabUIStates.has('tab-1')).toBe(false);
      expect(store.getState().tabUIStates.has('tab-2')).toBe(true);
    });

    it('should do nothing if tab does not exist', () => {
      store.getState().initTabUIState('tab-1');

      store.getState().cleanupTabUIState('nonexistent');

      expect(store.getState().tabUIStates.size).toBe(1);
    });
  });

  describe('AI Group expansion - per-tab isolation', () => {
    it('should toggle AI group expansion for specific tab', () => {
      store.getState().initTabUIState('tab-1');

      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(false);

      store.getState().toggleAIGroupExpansionForTab('tab-1', 'group-1');
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(true);

      store.getState().toggleAIGroupExpansionForTab('tab-1', 'group-1');
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(false);
    });

    it('should isolate AI group expansion between tabs', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().initTabUIState('tab-2');

      // Expand group-1 in tab-1 only
      store.getState().toggleAIGroupExpansionForTab('tab-1', 'group-1');

      // tab-1 should have it expanded, tab-2 should not
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(true);
      expect(store.getState().isAIGroupExpandedForTab('tab-2', 'group-1')).toBe(false);

      // Expand different group in tab-2
      store.getState().toggleAIGroupExpansionForTab('tab-2', 'group-2');

      // Each tab has its own expansion state
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(true);
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-2')).toBe(false);
      expect(store.getState().isAIGroupExpandedForTab('tab-2', 'group-1')).toBe(false);
      expect(store.getState().isAIGroupExpandedForTab('tab-2', 'group-2')).toBe(true);
    });

    it('should expand AI group programmatically', () => {
      store.getState().initTabUIState('tab-1');

      store.getState().expandAIGroupForTab('tab-1', 'group-1');
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(true);

      // Calling expand again should not change state (idempotent)
      store.getState().expandAIGroupForTab('tab-1', 'group-1');
      expect(store.getState().isAIGroupExpandedForTab('tab-1', 'group-1')).toBe(true);
    });
  });

  describe('Display item expansion - per-tab isolation', () => {
    it('should toggle display item expansion within AI group', () => {
      store.getState().initTabUIState('tab-1');

      const items = store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1');
      expect(items.size).toBe(0);

      store.getState().toggleDisplayItemExpansionForTab('tab-1', 'group-1', 'item-1');

      const updatedItems = store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1');
      expect(updatedItems.has('item-1')).toBe(true);

      store.getState().toggleDisplayItemExpansionForTab('tab-1', 'group-1', 'item-1');

      const finalItems = store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1');
      expect(finalItems.has('item-1')).toBe(false);
    });

    it('should isolate display item expansion between tabs', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().initTabUIState('tab-2');

      // Expand item in tab-1
      store.getState().toggleDisplayItemExpansionForTab('tab-1', 'group-1', 'item-1');

      // tab-1 should have it, tab-2 should not
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1').has('item-1')
      ).toBe(true);
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-2', 'group-1').has('item-1')
      ).toBe(false);
    });

    it('should isolate display items by AI group within same tab', () => {
      store.getState().initTabUIState('tab-1');

      store.getState().toggleDisplayItemExpansionForTab('tab-1', 'group-1', 'item-1');
      store.getState().toggleDisplayItemExpansionForTab('tab-1', 'group-2', 'item-2');

      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1').has('item-1')
      ).toBe(true);
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1').has('item-2')
      ).toBe(false);
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-2').has('item-1')
      ).toBe(false);
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-2').has('item-2')
      ).toBe(true);
    });

    it('should expand display item programmatically', () => {
      store.getState().initTabUIState('tab-1');

      store.getState().expandDisplayItemForTab('tab-1', 'group-1', 'item-1');
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1').has('item-1')
      ).toBe(true);

      // Calling expand again should not change state (idempotent)
      store.getState().expandDisplayItemForTab('tab-1', 'group-1', 'item-1');
      expect(
        store.getState().getExpandedDisplayItemIdsForTab('tab-1', 'group-1').has('item-1')
      ).toBe(true);
    });
  });

  describe('Subagent trace expansion - per-tab isolation', () => {
    it('should toggle subagent trace expansion', () => {
      store.getState().initTabUIState('tab-1');

      expect(store.getState().isSubagentTraceExpandedForTab('tab-1', 'subagent-1')).toBe(false);

      store.getState().toggleSubagentTraceExpansionForTab('tab-1', 'subagent-1');
      expect(store.getState().isSubagentTraceExpandedForTab('tab-1', 'subagent-1')).toBe(true);

      store.getState().toggleSubagentTraceExpansionForTab('tab-1', 'subagent-1');
      expect(store.getState().isSubagentTraceExpandedForTab('tab-1', 'subagent-1')).toBe(false);
    });

    it('should isolate subagent trace expansion between tabs', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().initTabUIState('tab-2');

      store.getState().toggleSubagentTraceExpansionForTab('tab-1', 'subagent-1');

      expect(store.getState().isSubagentTraceExpandedForTab('tab-1', 'subagent-1')).toBe(true);
      expect(store.getState().isSubagentTraceExpandedForTab('tab-2', 'subagent-1')).toBe(false);
    });
  });

  describe('Context panel visibility - per-tab isolation', () => {
    it('should set context panel visibility', () => {
      store.getState().initTabUIState('tab-1');

      expect(store.getState().isContextPanelVisibleForTab('tab-1')).toBe(false);

      store.getState().setContextPanelVisibleForTab('tab-1', true);
      expect(store.getState().isContextPanelVisibleForTab('tab-1')).toBe(true);

      store.getState().setContextPanelVisibleForTab('tab-1', false);
      expect(store.getState().isContextPanelVisibleForTab('tab-1')).toBe(false);
    });

    it('should isolate context panel visibility between tabs', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().initTabUIState('tab-2');

      store.getState().setContextPanelVisibleForTab('tab-1', true);

      expect(store.getState().isContextPanelVisibleForTab('tab-1')).toBe(true);
      expect(store.getState().isContextPanelVisibleForTab('tab-2')).toBe(false);
    });
  });

  describe('Scroll position - per-tab isolation', () => {
    it('should save and retrieve scroll position', () => {
      store.getState().initTabUIState('tab-1');

      expect(store.getState().getScrollPositionForTab('tab-1')).toBeUndefined();

      store.getState().saveScrollPositionForTab('tab-1', 500);
      expect(store.getState().getScrollPositionForTab('tab-1')).toBe(500);

      store.getState().saveScrollPositionForTab('tab-1', 1000);
      expect(store.getState().getScrollPositionForTab('tab-1')).toBe(1000);
    });

    it('should isolate scroll positions between tabs', () => {
      store.getState().initTabUIState('tab-1');
      store.getState().initTabUIState('tab-2');

      store.getState().saveScrollPositionForTab('tab-1', 100);
      store.getState().saveScrollPositionForTab('tab-2', 200);

      expect(store.getState().getScrollPositionForTab('tab-1')).toBe(100);
      expect(store.getState().getScrollPositionForTab('tab-2')).toBe(200);
    });
  });

  describe('Integration with tab lifecycle', () => {
    it('should handle full tab lifecycle', () => {
      // Simulate opening a tab
      store.getState().openTab({
        type: 'session',
        sessionId: 'session-1',
        projectId: 'project-1',
        label: 'Session 1',
      });
      const tabId = store.getState().activeTabId!;

      // Initialize UI state
      store.getState().initTabUIState(tabId);

      // Set some UI state
      store.getState().toggleAIGroupExpansionForTab(tabId, 'group-1');
      store.getState().setContextPanelVisibleForTab(tabId, true);
      store.getState().saveScrollPositionForTab(tabId, 300);

      // Verify state
      expect(store.getState().isAIGroupExpandedForTab(tabId, 'group-1')).toBe(true);
      expect(store.getState().isContextPanelVisibleForTab(tabId)).toBe(true);
      expect(store.getState().getScrollPositionForTab(tabId)).toBe(300);

      // Close tab (should cleanup UI state)
      store.getState().closeTab(tabId);

      // UI state should be cleaned up
      expect(store.getState().tabUIStates.has(tabId)).toBe(false);
    });

    it('should maintain separate state for two tabs with same session (forceNewTab)', () => {
      // Open first tab
      store.getState().openTab({
        type: 'session',
        sessionId: 'session-1',
        projectId: 'project-1',
        label: 'Session 1',
      });
      const tab1Id = store.getState().activeTabId!;
      store.getState().initTabUIState(tab1Id);

      // Open second tab with same session (forceNewTab)
      store.getState().openTab(
        {
          type: 'session',
          sessionId: 'session-1',
          projectId: 'project-1',
          label: 'Session 1 (Copy)',
        },
        { forceNewTab: true }
      );
      const tab2Id = store.getState().activeTabId!;
      store.getState().initTabUIState(tab2Id);

      // Both tabs should have same session
      expect(store.getState().openTabs.filter((t) => t.sessionId === 'session-1')).toHaveLength(2);

      // Set different states for each tab
      store.getState().toggleAIGroupExpansionForTab(tab1Id, 'group-1');
      store.getState().toggleAIGroupExpansionForTab(tab2Id, 'group-2');
      store.getState().setContextPanelVisibleForTab(tab1Id, true);
      store.getState().saveScrollPositionForTab(tab1Id, 100);
      store.getState().saveScrollPositionForTab(tab2Id, 500);

      // Verify states are isolated
      expect(store.getState().isAIGroupExpandedForTab(tab1Id, 'group-1')).toBe(true);
      expect(store.getState().isAIGroupExpandedForTab(tab1Id, 'group-2')).toBe(false);
      expect(store.getState().isAIGroupExpandedForTab(tab2Id, 'group-1')).toBe(false);
      expect(store.getState().isAIGroupExpandedForTab(tab2Id, 'group-2')).toBe(true);

      expect(store.getState().isContextPanelVisibleForTab(tab1Id)).toBe(true);
      expect(store.getState().isContextPanelVisibleForTab(tab2Id)).toBe(false);

      expect(store.getState().getScrollPositionForTab(tab1Id)).toBe(100);
      expect(store.getState().getScrollPositionForTab(tab2Id)).toBe(500);
    });
  });

  describe('Edge cases', () => {
    it('should return false/empty for uninitialized tab', () => {
      // No initialization
      expect(store.getState().isAIGroupExpandedForTab('nonexistent', 'group-1')).toBe(false);
      expect(store.getState().getExpandedDisplayItemIdsForTab('nonexistent', 'group-1').size).toBe(
        0
      );
      expect(store.getState().isSubagentTraceExpandedForTab('nonexistent', 'subagent-1')).toBe(
        false
      );
      expect(store.getState().isContextPanelVisibleForTab('nonexistent')).toBe(false);
      expect(store.getState().getScrollPositionForTab('nonexistent')).toBeUndefined();
    });

    it('should auto-create tab state when toggling (lazy initialization)', () => {
      // Toggle without explicit init
      store.getState().toggleAIGroupExpansionForTab('lazy-tab', 'group-1');

      // Should have created the state
      expect(store.getState().tabUIStates.has('lazy-tab')).toBe(true);
      expect(store.getState().isAIGroupExpandedForTab('lazy-tab', 'group-1')).toBe(true);
    });
  });
});
