import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import PropertyPanel from '../PropertyPanel';

jest.mock('react-icons/fi', () => ({
  FiChevronDown: () => <span data-testid="fi-chevron-down" />,
  FiChevronRight: () => <span data-testid="fi-chevron-right" />,
  FiChevronLeft: () => <span data-testid="fi-chevron-left" />,
  FiActivity: () => <span data-testid="fi-activity" />,
  FiZap: () => <span data-testid="fi-zap" />,
  FiGitBranch: () => <span data-testid="fi-git-branch" />,
  FiBox: () => <span data-testid="fi-box" />,
  FiLock: () => <span data-testid="fi-lock" />,
  FiUnlock: () => <span data-testid="fi-unlock" />,
  FiInfo: () => <span data-testid="fi-info" />,
}));

jest.mock('../DocumentationButton', () => () => <span data-testid="doc-btn" />);
jest.mock('../InfoPopup', () => {
  const MockInfoPopup = (props: any) => <div data-testid="info-popup">{props.items?.map((item: any, i: number) => <span key={i}>{item.label}: {item.value}</span>)}</div>;
  MockInfoPopup.displayName = 'MockInfoPopup';
  return MockInfoPopup;
});
jest.mock('../MultiSelectionPanel', () => (_props: any) => <div data-testid="multi-selection-panel" />);
jest.mock('../NodePropertiesPanel', () => (props: any) => <div data-testid="node-properties-panel" data-node-id={props.node?.id} />);
jest.mock('../EdgePropertiesPanel', () => (props: any) => <div data-testid="edge-properties-panel" data-edge-id={props.edge?.id} />);

const mockTogglePropertyPanelCollapse = jest.fn();
let mockStoreState: any = {
  panelWidth: 300,
  panelIsResizing: false,
  setPanelWidth: jest.fn(),
  setPanelResizing: jest.fn(),
  propertyPanelCollapsed: false,
  togglePropertyPanelCollapse: mockTogglePropertyPanelCollapse,
  components: [],
  selectedEdge: null,
};

jest.mock('../../store/store', () => ({
  useStore: jest.fn(() => mockStoreState),
}));

jest.mock('../../hooks/useConfigurationLoader', () => ({
  useConfigurationLoader: jest.fn(() => ({
    configurationForm: null,
    loading: false,
  })),
}));

jest.mock('../../hooks/usePanelResize', () => ({
  usePanelResize: jest.fn(() => ({
    startResize: jest.fn(),
  })),
}));

jest.mock('../../hooks/useDebouncedField', () => ({
  useDebouncedField: jest.fn(({ initialValue }) => ({
    value: initialValue || '',
    setValue: jest.fn(),
    onChange: jest.fn(),
    onBlur: jest.fn(),
  })),
}));

describe('PropertyPanel', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockStoreState = {
      panelWidth: 300,
      panelIsResizing: false,
      setPanelWidth: jest.fn(),
      setPanelResizing: jest.fn(),
      propertyPanelCollapsed: false,
      togglePropertyPanelCollapse: mockTogglePropertyPanelCollapse,
      components: [],
      selectedEdge: null,
    };
  });

  describe('empty state', () => {
    it('should show empty message when no node or edge selected', () => {
      render(<PropertyPanel />);
      expect(screen.getByText('Select a component or connection to view its properties')).toBeTruthy();
    });
  });

  describe('single node selected', () => {
    it('should render NodePropertiesPanel', () => {
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByTestId('node-properties-panel')).toBeTruthy();
    });

    it('should show component type for element nodes', () => {
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByText('Element')).toBeTruthy();
    });

    it('should show Start type for start nodes', () => {
      const node = { id: 'node-1', type: 'start', data: { label: 'Test', plugin: 'test' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByText('Start')).toBeTruthy();
    });

    it('should show Gateway type for gateway nodes', () => {
      const node = { id: 'node-1', type: 'gateway', data: { label: 'Test', plugin: 'test' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByText('Gateway')).toBeTruthy();
    });
  });

  describe('single edge selected', () => {
    it('should render EdgePropertiesPanel', () => {
      const edge = { id: 'edge-1', source: 'a', target: 'b', data: { condition: 'test' } };
      render(<PropertyPanel edge={edge as any} />);
      expect(screen.getByTestId('edge-properties-panel')).toBeTruthy();
    });

    it('should show Link type', () => {
      const edge = { id: 'edge-1', source: 'a', target: 'b', data: { condition: 'test' } };
      render(<PropertyPanel edge={edge as any} />);
      expect(screen.getByText('Link')).toBeTruthy();
    });
  });

  describe('multi-selection', () => {
    it('should render MultiSelectionPanel when multiple nodes selected', () => {
      const nodes = [
        { id: 'n1', type: 'element', data: { label: 'A' }, position: { x: 0, y: 0 } },
        { id: 'n2', type: 'element', data: { label: 'B' }, position: { x: 0, y: 0 } },
      ];
      render(<PropertyPanel selectedNodes={nodes as any} />);
      expect(screen.getByTestId('multi-selection-panel')).toBeTruthy();
      expect(screen.getByText('Multiple Selection')).toBeTruthy();
    });
  });

  describe('lock button', () => {
    it('should show unlock button for unlocked node', () => {
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test', locked: false }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByTitle('Lock')).toBeTruthy();
    });

    it('should show lock button for locked node', () => {
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test', locked: true }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByTitle('Unlock')).toBeTruthy();
    });

    it('should call onConfigurationChange when node lock button clicked', () => {
      const onConfigurationChange = jest.fn();
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test', locked: false }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} onConfigurationChange={onConfigurationChange} />);
      fireEvent.click(screen.getByTitle('Lock'));
      expect(onConfigurationChange).toHaveBeenCalledWith('node-1', { _componentLocked: true });
    });

    it('should call onEdgeConfigurationChange when edge lock button clicked', () => {
      const onEdgeConfigurationChange = jest.fn();
      const edge = { id: 'edge-1', source: 'a', target: 'b', data: { condition: 'test', locked: false } };
      render(<PropertyPanel edge={edge as any} onEdgeConfigurationChange={onEdgeConfigurationChange} />);
      fireEvent.click(screen.getByTitle('Lock'));
      expect(onEdgeConfigurationChange).toHaveBeenCalledWith('edge-1', expect.objectContaining({ edgeLocked: true }));
    });

    it('should not call handler when globally locked', () => {
      const onConfigurationChange = jest.fn();
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test', locked: false }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} onConfigurationChange={onConfigurationChange} isLocked={true} />);
      const lockBtn = screen.getByTitle('Lock');
      expect(lockBtn).toBeDisabled();
    });
  });

  describe('subprocess type', () => {
    it('should show Subprocess type for subprocess nodes', () => {
      const node = { id: 'node-1', type: 'subprocess', data: { label: 'Test', plugin: 'test' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByText('Subprocess')).toBeTruthy();
    });
  });

  describe('loading indicator', () => {
    it('should show loading indicator when configuration is loading', () => {
      const { useConfigurationLoader } = require('../../hooks/useConfigurationLoader');
      useConfigurationLoader.mockReturnValue({ configurationForm: null, loading: true });
      
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByText('Loading...')).toBeTruthy();
    });
  });

  describe('documentation button', () => {
    it('should show documentation button when component has documentationUrl', () => {
      mockStoreState.components = [{ plugin: 'test_plugin', documentationUrl: 'https://example.com/docs' }];
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test_plugin' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByTestId('doc-btn')).toBeTruthy();
    });

    it('should show documentation button from node data documentationUrl', () => {
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'test_plugin', documentationUrl: 'https://example.com' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.getByTestId('doc-btn')).toBeTruthy();
    });

    it('should not show documentation button when no URL available', () => {
      const node = { id: 'node-1', type: 'element', data: { label: 'Test', plugin: 'no_docs' }, position: { x: 0, y: 0 } };
      render(<PropertyPanel node={node as any} />);
      expect(screen.queryByTestId('doc-btn')).toBeFalsy();
    });
  });

  describe('collapsed state', () => {
    it('should show collapsed label when collapsed', () => {
      mockStoreState.propertyPanelCollapsed = true;
      render(<PropertyPanel />);
      expect(screen.getByText('Properties')).toBeTruthy();
    });

    it('should expand panel when collapsed panel clicked', () => {
      mockStoreState.propertyPanelCollapsed = true;
      render(<PropertyPanel />);
      const panel = document.querySelector('.workflow-property-panel');
      fireEvent.click(panel!);
      expect(mockTogglePropertyPanelCollapse).toHaveBeenCalled();
    });

    it('should not toggle collapse when clicking expanded panel', () => {
      mockStoreState.propertyPanelCollapsed = false;
      render(<PropertyPanel />);
      const panel = document.querySelector('.workflow-property-panel');
      fireEvent.click(panel!);
      expect(mockTogglePropertyPanelCollapse).not.toHaveBeenCalled();
    });

    it('should toggle collapse when collapse widget clicked', () => {
      render(<PropertyPanel />);
      const collapseWidget = document.querySelector('.panel-collapse-widget');
      fireEvent.click(collapseWidget!);
      expect(mockTogglePropertyPanelCollapse).toHaveBeenCalled();
    });
  });

  describe('resizing state', () => {
    it('should apply resizing class when panel is resizing', () => {
      mockStoreState.panelIsResizing = true;
      render(<PropertyPanel />);
      const panel = document.querySelector('.workflow-property-panel');
      expect(panel?.className).toContain('resizing');
    });
  });

  describe('edge with condition configuration', () => {
    it('should show edge lock button for locked edge', () => {
      const edge = { id: 'edge-1', source: 'a', target: 'b', data: { condition: 'test', locked: true } };
      render(<PropertyPanel edge={edge as any} />);
      expect(screen.getByTitle('Unlock')).toBeTruthy();
    });
  });

  describe('multi-selection with edges', () => {
    it('should render MultiSelectionPanel when multiple edges selected', () => {
      const edges = [
        { id: 'e1', source: 'a', target: 'b', data: {} },
        { id: 'e2', source: 'b', target: 'c', data: {} },
      ];
      render(<PropertyPanel selectedEdges={edges as any} />);
      expect(screen.getByTestId('multi-selection-panel')).toBeTruthy();
    });

    it('should render MultiSelectionPanel when nodes and edges both selected', () => {
      const nodes = [
        { id: 'n1', type: 'element', data: { label: 'A' }, position: { x: 0, y: 0 } },
      ];
      const edges = [
        { id: 'e1', source: 'a', target: 'b', data: {} },
      ];
      render(<PropertyPanel selectedNodes={nodes as any} selectedEdges={edges as any} />);
      expect(screen.getByTestId('multi-selection-panel')).toBeTruthy();
    });
  });
});
