import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { getPanelPlugin } from '@grafana/data/test';
import { selectors } from '@grafana/e2e-selectors';
import { setPluginImportUtils } from '@grafana/runtime';
import { SceneVariableSet, VizPanel } from '@grafana/scenes';
import { ElementSelectionContext, Sidebar, useSidebar } from '@grafana/ui';

import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
import { DashboardScene } from '../scene/DashboardScene';
import { AutoGridItem } from '../scene/layout-auto-grid/AutoGridItem';
import { AutoGridLayout } from '../scene/layout-auto-grid/AutoGridLayout';
import { AutoGridLayoutManager } from '../scene/layout-auto-grid/AutoGridLayoutManager';
import { RowItem } from '../scene/layout-rows/RowItem';
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
import { TabItem } from '../scene/layout-tabs/TabItem';
import { TabsLayoutManager } from '../scene/layout-tabs/TabsLayoutManager';
import { DashboardInteractions } from '../utils/interactions';
import { activateFullSceneTree } from '../utils/test-utils';

import { DashboardOutline } from './DashboardOutline';

jest.mock('../utils/interactions', () => ({
  DashboardInteractions: {
    outlineItemClicked: jest.fn(),
  },
}));

setPluginImportUtils({
  importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})),
  getPanelPluginFromCache: (id: string) => undefined,
});
const testScene = new DashboardScene({
  title: 'Test Dashboard',
  $variables: new SceneVariableSet({ variables: [] }),
  $data: new DashboardDataLayerSet({ annotationLayers: [] }),
  body: new RowsLayoutManager({
    rows: [
      new RowItem({
        title: 'Row level 1',
        layout: new RowsLayoutManager({
          rows: [
            new RowItem({
              title: 'Row level 2',
              layout: new TabsLayoutManager({
                tabs: [
                  new TabItem({
                    title: 'Tab level 3 - A',
                    layout: new AutoGridLayoutManager({
                      layout: new AutoGridLayout({
                        children: [
                          new AutoGridItem({
                            body: new VizPanel({
                              title: 'Panel level 4 - A',
                            }),
                          }),
                        ],
                      }),
                    }),
                  }),
                  new TabItem({
                    title: 'Tab level 3 - B',
                    layout: new AutoGridLayoutManager({
                      layout: new AutoGridLayout({
                        children: [
                          new AutoGridItem({
                            body: new VizPanel({
                              title: 'Panel level 4 - A',
                            }),
                          }),
                        ],
                      }),
                    }),
                  }),
                ],
              }),
            }),
          ],
        }),
      }),
    ],
  }),
});

function buildTestScene() {
  activateFullSceneTree(testScene);
  return testScene;
}

function WrapSidebar({ children }: { children: React.ReactElement }) {
  const sidebarContext = useSidebar({});

  return <Sidebar contextValue={sidebarContext}>{children}</Sidebar>;
}

describe('DashboardOutline', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('outline item interactions tracking', () => {
    it('should call DashboardInteractions.outlineItemClicked with correct parameters when clicking on items', async () => {
      const user = userEvent.setup();
      const scene = buildTestScene();

      // enable selection on the edit pane to activate real selection behavior
      scene.state.editPane.enableSelection();

      render(
        <ElementSelectionContext.Provider value={scene.state.editPane.state.selectionContext}>
          <WrapSidebar>
            <DashboardOutline editPane={scene.state.editPane} isEditing={true} />
          </WrapSidebar>
        </ElementSelectionContext.Provider>
      );
      // select Row lvl 1 (index 3 because Variables is at 0, Annotations at 1, Links at 2)
      await user.click(screen.getByTestId(selectors.components.PanelEditor.Outline.item('Row level 1')));
      expect(DashboardInteractions.outlineItemClicked).toHaveBeenNthCalledWith(1, {
        index: 3,
        depth: 1,
        isEditing: true,
      });
      // click on caret to expand Row lvl 1
      await user.click(screen.getByTestId(selectors.components.PanelEditor.Outline.node('Row level 1')));

      // select Row lvl 2
      await user.click(screen.getByTestId(selectors.components.PanelEditor.Outline.item('Row level 2')));
      expect(DashboardInteractions.outlineItemClicked).toHaveBeenNthCalledWith(2, {
        index: 0,
        depth: 2,
        isEditing: true,
      });

      // click on caret to expand Row lvl 2
      await user.click(screen.getByTestId(selectors.components.PanelEditor.Outline.node('Row level 2')));

      // select Tab lvl 3 - B
      await user.click(screen.getByTestId(selectors.components.PanelEditor.Outline.item('Tab level 3 - B')));
      expect(DashboardInteractions.outlineItemClicked).toHaveBeenNthCalledWith(3, {
        index: 1,
        depth: 3,
        isEditing: true,
      });
    });

    it('should call DashboardInteractions.outlineItemClicked with correct parameters when not in edit mode', async () => {
      const user = userEvent.setup();
      const scene = buildTestScene();

      // enable selection on the edit pane to activate real selection behavior
      scene.state.editPane.enableSelection();

      render(
        <ElementSelectionContext.Provider value={scene.state.editPane.state.selectionContext}>
          <WrapSidebar>
            <DashboardOutline editPane={scene.state.editPane} isEditing={false} />
          </WrapSidebar>
        </ElementSelectionContext.Provider>
      );
      // select Row lvl 1 (index 0 because variables and annotations aren't shown in view mode)
      await user.click(screen.getByTestId(selectors.components.PanelEditor.Outline.item('Row level 1')));
      expect(DashboardInteractions.outlineItemClicked).toHaveBeenNthCalledWith(1, {
        index: 0,
        depth: 1,
        isEditing: false,
      });
    });
  });
});
