/**
 * WorkflowReactFlowNode Tests
 *
 * Tests the custom React Flow node component including:
 * - Placeholder node rendering
 * - Configured node rendering
 * - Status indicators
 * - Selection states
 * - Action callbacks
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import WorkflowReactFlowNode from './WorkflowReactFlowNode';
import { WorkflowNodeData } from '../types/reactflow';

// Mock ServiceIcon
vi.mock('./ServiceIcon', () => ({
  ServiceIcon: ({ service, size }: { service: string; size: number }) => (
    <span data-testid="service-icon" data-service={service} data-size={size}>
      Icon
    </span>
  ),
}));

// Mock NodeActionsMenu
vi.mock('./NodeActionsMenu', () => ({
  default: ({
    nodeId,
    onEdit,
    onDelete,
    onDuplicate,
    onViewDataFields,
  }: {
    nodeId: string;
    onEdit?: () => void;
    onDelete?: () => void;
    onDuplicate?: () => void;
    onViewDataFields?: () => void;
  }) => (
    <div data-testid="node-actions-menu" data-node-id={nodeId}>
      {onEdit && (
        <button data-testid="edit-btn" onClick={onEdit}>
          Edit
        </button>
      )}
      {onDuplicate && (
        <button data-testid="duplicate-btn" onClick={onDuplicate}>
          Duplicate
        </button>
      )}
      {onDelete && (
        <button data-testid="delete-btn" onClick={onDelete}>
          Delete
        </button>
      )}
      {onViewDataFields && (
        <button data-testid="view-fields-btn" onClick={onViewDataFields}>
          View Fields
        </button>
      )}
    </div>
  ),
}));

// Mock React Flow components
vi.mock('@xyflow/react', () => ({
  Handle: ({ type, position }: { type: string; position: string }) => (
    <div data-testid={`handle-${type}`} data-position={position} />
  ),
  Position: {
    Top: 'top',
    Bottom: 'bottom',
    Left: 'left',
    Right: 'right',
  },
  useUpdateNodeInternals: () => vi.fn(),
}));

describe('WorkflowReactFlowNode', () => {
  const baseData: WorkflowNodeData = {
    name: 'User Registration',
    icon: 'UserPlus',
    status: 'valid',
    config: {},
    actionType: 'wordpress/user_registration',
    appName: 'WordPress',
    appService: 'wordpress',
    stepNumber: 1,
  };

  const baseProps = {
    id: 'node-1',
    data: baseData,
    selected: false,
    type: 'trigger' as const,
    xPos: 0,
    yPos: 0,
    zIndex: 0,
    isConnectable: true,
    positionAbsoluteX: 0,
    positionAbsoluteY: 0,
    dragging: false,
    draggable: true,
    deletable: true,
    selectable: true,
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  // ==========================================================================
  // Placeholder Node Tests
  // ==========================================================================

  describe('placeholder node', () => {
    const placeholderData: WorkflowNodeData = {
      ...baseData,
      status: 'placeholder',
      placeholderType: 'trigger',
    };

    it('renders placeholder node when status is placeholder', () => {
      render(<WorkflowReactFlowNode {...baseProps} data={placeholderData} />);

      expect(screen.getByText('Trigger')).toBeInTheDocument();
      expect(
        screen.getByText('Choose an app and event to start your workflow'),
      ).toBeInTheDocument();
    });

    it('renders action placeholder with correct text', () => {
      render(
        <WorkflowReactFlowNode
          {...baseProps}
          data={{ ...placeholderData, placeholderType: 'action' }}
          type="action"
        />,
      );

      expect(screen.getByText('Action')).toBeInTheDocument();
      expect(screen.getByText('Select the event for your workflow to run')).toBeInTheDocument();
    });

    it('calls onSelectApp when placeholder is clicked', async () => {
      const onSelectApp = vi.fn();
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...placeholderData, onSelectApp }} />);

      // Find the clickable div containing the placeholder content
      const placeholder = screen
        .getByText('Choose an app and event to start your workflow')
        .closest('div[class*="cursor-pointer"]');
      await userEvent.click(placeholder!);

      expect(onSelectApp).toHaveBeenCalledWith('node-1');
    });

    it('renders source handle for trigger placeholder', () => {
      render(<WorkflowReactFlowNode {...baseProps} data={placeholderData} />);

      expect(screen.getByTestId('handle-source')).toBeInTheDocument();
    });

    it('renders target handle for action placeholder', () => {
      render(
        <WorkflowReactFlowNode
          {...baseProps}
          data={{ ...placeholderData, placeholderType: 'action' }}
          type="action"
        />,
      );

      expect(screen.getByTestId('handle-target')).toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Configured Node Tests
  // ==========================================================================

  describe('configured node', () => {
    it('renders node name', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      expect(screen.getByText('User Registration')).toBeInTheDocument();
    });

    it('renders app name', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      expect(screen.getByText('WordPress')).toBeInTheDocument();
    });

    it('renders step number', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      expect(screen.getByText('Step 1')).toBeInTheDocument();
    });

    it('renders service icon', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      expect(screen.getByTestId('service-icon')).toHaveAttribute('data-service', 'wordpress');
    });

    it('uses fallback app name when not provided', () => {
      const dataWithoutApp = { ...baseData, appName: undefined };
      render(<WorkflowReactFlowNode {...baseProps} data={dataWithoutApp as any} />);

      expect(screen.getByText('WordPress')).toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Status Indicator Tests
  // ==========================================================================

  describe('status indicators', () => {
    it('renders valid status with CheckCircle', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      // CheckCircle should have success color class
      const statusIcon = document.querySelector('.text-\\[var\\(--seq-success\\)\\]');
      expect(statusIcon).toBeInTheDocument();
    });

    it('renders error status with AlertCircle', () => {
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...baseData, status: 'error' }} />);

      const statusIcon = document.querySelector('.text-\\[var\\(--seq-error\\)\\]');
      expect(statusIcon).toBeInTheDocument();
    });

    it('renders warning status with AlertTriangle', () => {
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...baseData, status: 'warning' }} />);

      const statusIcon = document.querySelector('.text-\\[var\\(--seq-warning\\)\\]');
      expect(statusIcon).toBeInTheDocument();
    });

    it('renders unconfigured status with Settings icon', () => {
      render(
        <WorkflowReactFlowNode {...baseProps} data={{ ...baseData, status: 'unconfigured' }} />,
      );

      const statusIcon = document.querySelector('.status-icon');
      expect(statusIcon).toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Handle Tests
  // ==========================================================================

  describe('handles', () => {
    it('renders only source handle for trigger nodes', () => {
      render(<WorkflowReactFlowNode {...baseProps} type="trigger" />);

      expect(screen.getByTestId('handle-source')).toBeInTheDocument();
      expect(screen.queryByTestId('handle-target')).not.toBeInTheDocument();
    });

    it('renders both handles for action nodes', () => {
      render(<WorkflowReactFlowNode {...baseProps} type="action" />);

      expect(screen.getByTestId('handle-source')).toBeInTheDocument();
      expect(screen.getByTestId('handle-target')).toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Selection Style Tests
  // ==========================================================================

  describe('selection styles', () => {
    it('applies trigger glow when selected trigger', () => {
      render(<WorkflowReactFlowNode {...baseProps} type="trigger" selected={true} />);

      const node = document.querySelector('.shadow-glow-trigger');
      expect(node).toBeInTheDocument();
    });

    it('applies action glow when selected action', () => {
      render(<WorkflowReactFlowNode {...baseProps} type="action" selected={true} />);

      const node = document.querySelector('.shadow-glow-action');
      expect(node).toBeInTheDocument();
    });

    it('applies operator glow when selected operator', () => {
      render(<WorkflowReactFlowNode {...baseProps} type="operator" selected={true} />);

      const node = document.querySelector('.shadow-glow-operator');
      expect(node).toBeInTheDocument();
    });

    it('does not apply glow when not selected', () => {
      render(<WorkflowReactFlowNode {...baseProps} type="trigger" selected={false} />);

      const node = document.querySelector('.shadow-glow-trigger');
      expect(node).not.toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Actions Menu Tests
  // ==========================================================================

  describe('actions menu', () => {
    it('renders actions menu when callbacks are provided', () => {
      const onEdit = vi.fn();
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...baseData, onEdit }} />);

      expect(screen.getByTestId('node-actions-menu')).toBeInTheDocument();
    });

    it('does not render actions menu when no callbacks', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      expect(screen.queryByTestId('node-actions-menu')).not.toBeInTheDocument();
    });

    it('calls onEdit when edit action is clicked', async () => {
      const onEdit = vi.fn();
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...baseData, onEdit }} />);

      await userEvent.click(screen.getByTestId('edit-btn'));
      expect(onEdit).toHaveBeenCalledWith('node-1');
    });

    it('calls onDelete when delete action is clicked', async () => {
      const onDelete = vi.fn();
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...baseData, onDelete }} />);

      await userEvent.click(screen.getByTestId('delete-btn'));
      expect(onDelete).toHaveBeenCalledWith('node-1');
    });

    it('calls onDuplicate when duplicate action is clicked', async () => {
      const onDuplicate = vi.fn();
      render(<WorkflowReactFlowNode {...baseProps} data={{ ...baseData, onDuplicate }} />);

      await userEvent.click(screen.getByTestId('duplicate-btn'));
      expect(onDuplicate).toHaveBeenCalledWith('node-1');
    });

    it('calls onViewDataFields for trigger nodes', async () => {
      const onViewDataFields = vi.fn();
      render(
        <WorkflowReactFlowNode
          {...baseProps}
          type="trigger"
          data={{ ...baseData, onEdit: vi.fn(), onViewDataFields }}
        />,
      );

      await userEvent.click(screen.getByTestId('view-fields-btn'));
      expect(onViewDataFields).toHaveBeenCalledWith('node-1');
    });
  });

  // ==========================================================================
  // Config Summary Tests
  // ==========================================================================

  describe('config summary', () => {
    it('renders config summary when provided', () => {
      render(
        <WorkflowReactFlowNode
          {...baseProps}
          data={{ ...baseData, configSummary: 'Send to user@example.com' }}
        />,
      );

      expect(screen.getByText('Send to user@example.com')).toBeInTheDocument();
    });

    it('does not render config summary section when not provided', () => {
      render(<WorkflowReactFlowNode {...baseProps} />);

      // Check there's no border-t div for the summary section
      expect(screen.queryByText('Send to')).not.toBeInTheDocument();
    });

    it('renders field count for trigger nodes', () => {
      render(
        <WorkflowReactFlowNode
          {...baseProps}
          type="trigger"
          data={{ ...baseData, fieldCount: 5 }}
        />,
      );

      expect(screen.getByText('5 fields')).toBeInTheDocument();
    });
  });
});
