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

// Mock ConfigurationForm
jest.mock('../ConfigurationForm', () => {
  return function MockConfigurationForm(props: any) {
    return <div data-testid="configuration-form" data-disabled={props.disabled} />;
  };
});

// Mock react-icons (none currently used, but keep mock to prevent import errors)
jest.mock('react-icons/fi', () => ({}));

// Mock the Zustand store
let mockIsTokenDragging = false;
jest.mock('../../store/store', () => ({
  useStore: jest.fn((selector: any) => {
    const state = {
      isTokenDragging: mockIsTokenDragging,
    };
    if (typeof selector === 'function') return selector(state);
    return state;
  }),
}));

describe('NodePropertiesPanel', () => {
  const mockOnConfigurationChange = jest.fn();
  const mockOnNodeUpdate = jest.fn();

  const createMockField = (value: string = '') => ({
    value,
    setValue: jest.fn(),
    onChange: jest.fn(),
    onBlur: jest.fn(),
  });

  const defaultNode = {
    id: 'node-1',
    type: 'element',
    position: { x: 0, y: 0 },
    data: {
      label: 'Test Node',
      plugin: 'test.action.test',
      description: 'A test node',
      annotation: 'Some note',
      configuration: { field1: 'value1' },
    },
  };

  const defaultProps = {
    node: defaultNode as any,
    configurationForm: null,
    onConfigurationChange: mockOnConfigurationChange,
    onNodeUpdate: mockOnNodeUpdate,
    isLocked: false,
    nodeLabelField: createMockField('Test Node'),
    nodeAnnotationField: createMockField('Some note'),
  };

  beforeEach(() => {
    jest.clearAllMocks();
    mockIsTokenDragging = false;
  });

  describe('label input', () => {
    it('should render label input with node label', () => {
      render(<NodePropertiesPanel {...defaultProps} />);
      const input = screen.getByLabelText('Label');
      expect(input).toBeTruthy();
      expect((input as HTMLInputElement).value).toBe('Test Node');
    });

    it('should disable label input when locked', () => {
      render(<NodePropertiesPanel {...defaultProps} isLocked={true} />);
      const input = screen.getByLabelText('Label');
      expect(input).toBeDisabled();
    });

    it('should disable label input when node is individually locked', () => {
      const lockedNode = { ...defaultNode, data: { ...defaultNode.data, locked: true } };
      render(<NodePropertiesPanel {...defaultProps} node={lockedNode as any} />);
      const input = screen.getByLabelText('Label');
      expect(input).toBeDisabled();
    });
  });

  describe('description', () => {
    it('should render node description', () => {
      render(<NodePropertiesPanel {...defaultProps} />);
      expect(screen.getByText('A test node')).toBeTruthy();
    });

    it('should not render description when not present', () => {
      const nodeWithoutDesc = { ...defaultNode, data: { ...defaultNode.data, description: undefined } };
      render(<NodePropertiesPanel {...defaultProps} node={nodeWithoutDesc as any} />);
      expect(screen.queryByText('A test node')).toBeNull();
    });
  });

  describe('configuration form', () => {
    it('should render configuration form when provided', () => {
      render(<NodePropertiesPanel {...defaultProps} configurationForm={{ fields: [] }} />);
      expect(screen.getByTestId('configuration-form')).toBeTruthy();
    });

    it('should not render configuration form when null', () => {
      render(<NodePropertiesPanel {...defaultProps} configurationForm={null} />);
      expect(screen.queryByTestId('configuration-form')).toBeNull();
    });
  });

  describe('annotation field', () => {
    it('should render annotation textarea', () => {
      render(<NodePropertiesPanel {...defaultProps} />);
      const annotation = screen.getByLabelText('Annotation');
      expect(annotation).toBeTruthy();
      expect(annotation.tagName).toBe('TEXTAREA');
    });

    it('should show annotation value', () => {
      render(<NodePropertiesPanel {...defaultProps} />);
      const annotation = screen.getByLabelText('Annotation');
      expect(annotation).toHaveValue('Some note');
    });

    it('should disable annotation when locked', () => {
      render(<NodePropertiesPanel {...defaultProps} isLocked={true} />);
      const annotation = screen.getByLabelText('Annotation');
      expect(annotation).toBeDisabled();
    });
  });

  describe('token drag state', () => {
    it('should add token-drop-disabled class to native fields when token is being dragged', () => {
      mockIsTokenDragging = true;
      const { container } = render(<NodePropertiesPanel {...defaultProps} />);
      const nativeFields = container.querySelectorAll('.modeler-native-field.token-drop-disabled');
      expect(nativeFields.length).toBe(2); // label + annotation
    });

    it('should not add token-drop-disabled class when no token is being dragged', () => {
      mockIsTokenDragging = false;
      const { container } = render(<NodePropertiesPanel {...defaultProps} />);
      expect(container.querySelector('.modeler-native-field.token-drop-disabled')).toBeNull();
    });

    it('should prevent drop on label input during token drag', () => {
      mockIsTokenDragging = true;
      render(<NodePropertiesPanel {...defaultProps} />);
      const labelInput = screen.getByLabelText('Label');

      const dropEvent = new Event('drop', { bubbles: true, cancelable: true });
      const prevented = !labelInput.dispatchEvent(dropEvent);
      expect(prevented).toBe(true);
    });

    it('should prevent drop on annotation textarea during token drag', () => {
      mockIsTokenDragging = true;
      render(<NodePropertiesPanel {...defaultProps} />);
      const annotation = screen.getByLabelText('Annotation');

      const dropEvent = new Event('drop', { bubbles: true, cancelable: true });
      const prevented = !annotation.dispatchEvent(dropEvent);
      expect(prevented).toBe(true);
    });
  });
});
