/**
 * SplitContainer Component Tests
 *
 * Tests for the SplitContainer component that provides resizable split panels.
 */

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

describe('SplitContainer', () => {
  const defaultProps = {
    children: [
      <div key="left" data-testid="left-panel">Left Panel</div>,
      <div key="right" data-testid="right-panel">Right Panel</div>
    ]
  };

  beforeEach(() => {
    // Setup window.getComputedStyle mock - returns a CSSStyleDeclaration-like object
    window.getComputedStyle = jest.fn(() => ({
      getPropertyValue: (prop) => {
        const values = {
          'width': '800px',
          'height': '600px',
        };
        return values[prop] || '0px';
      },
      width: '800px',
      height: '600px',
    }));

    // Mock getBoundingClientRect
    Element.prototype.getBoundingClientRect = jest.fn(() => ({
      width: 800,
      height: 600,
      left: 0,
      top: 0,
      right: 800,
      bottom: 600
    }));
  });

  afterEach(() => {
    // Clean up any global state
    document.body.innerHTML = '';

    // Reset any global mocks
    if (document.onselectstart) {
      document.onselectstart = null;
    }
    if (document.ondragstart) {
      document.ondragstart = null;
    }
  });

  it('renders with default horizontal layout', () => {
    render(<SplitContainer {...defaultProps} />);

    expect(screen.getByTestId('left-panel')).toBeInTheDocument();
    expect(screen.getByTestId('right-panel')).toBeInTheDocument();

    const container = screen.getByTestId('left-panel').closest('.split-container');
    expect(container).toHaveClass('split-container--horizontal');
  });

  it('renders with vertical layout when specified', () => {
    render(<SplitContainer {...defaultProps} direction="vertical" />);

    const container = screen.getByTestId('left-panel').closest('.split-container');
    expect(container).toHaveClass('split-container--vertical');
  });

  it('applies default 50/50 split', () => {
    render(<SplitContainer {...defaultProps} />);

    const container = screen.getByTestId('left-panel').closest('.split-container');

    // Check CSS custom properties are set correctly
    expect(container.style.getPropertyValue('--split-size')).toBe('50%');
    expect(container.style.getPropertyValue('--remaining-size')).toBe('50%');
  });

  it('applies custom default split', () => {
    render(<SplitContainer {...defaultProps} defaultSplit={30} />);

    const container = screen.getByTestId('left-panel').closest('.split-container');

    // Check CSS custom properties are set correctly
    expect(container.style.getPropertyValue('--split-size')).toBe('30%');
    expect(container.style.getPropertyValue('--remaining-size')).toBe('70%');
  });

  it('renders splitter handle', () => {
    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');
    const handle = document.querySelector('.split-container__splitter-handle');
    const line = document.querySelector('.split-container__splitter-line');

    expect(splitter).toBeInTheDocument();
    expect(handle).toBeInTheDocument();
    expect(line).toBeInTheDocument();
  });

  it('handles mouse down on splitter', () => {
    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');

    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });

    const container = screen.getByTestId('left-panel').closest('.split-container');
    expect(container).toHaveClass('split-container--dragging');
  });

  it('handles mouse move during drag', () => {
    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');
    const container = screen.getByTestId('left-panel').closest('.split-container');

    // Start drag
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });

    // Move mouse
    fireEvent.mouseMove(document, { clientX: 300, clientY: 300 });

    // Should update split position via CSS custom properties
    const splitSize = container.style.getPropertyValue('--split-size');
    expect(splitSize).toBeTruthy();
    expect(splitSize).toMatch(/^\d+(\.\d+)?%$/); // Should be a percentage
  });

  it('handles mouse up to end drag', () => {
    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');

    // Start and end drag
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });
    fireEvent.mouseUp(document);

    const container = screen.getByTestId('left-panel').closest('.split-container');
    expect(container).not.toHaveClass('split-container--dragging');
  });

  it('handles touch events', () => {
    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');

    // Touch start
    fireEvent.touchStart(splitter, {
      touches: [{ clientX: 400, clientY: 300 }]
    });

    const container = screen.getByTestId('left-panel').closest('.split-container');
    expect(container).toHaveClass('split-container--dragging');
  });

  it('respects minimum size constraints', () => {
    render(<SplitContainer {...defaultProps} minSize={100} />);

    const splitter = document.querySelector('.split-container__splitter');

    // Try to drag to a very small size
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });
    fireEvent.mouseMove(document, { clientX: 50, clientY: 300 }); // Very small

    const firstPanel = screen.getByTestId('left-panel').closest('.split-container__panel--first');
    const container = firstPanel.closest('.split-container');

    // Read the CSS variable directly from the inline style
    const splitSizeValue = container.style.getPropertyValue('--split-size');
    const parsedPercent = parseFloat(splitSizeValue.trim().replace('%', ''));

    // Should respect minimum size (100px out of 800px = 12.5%)
    expect(parsedPercent).toBeGreaterThanOrEqual(12.5);
  });

  it('respects maximum size constraints', () => {
    render(<SplitContainer {...defaultProps} maxSize={100} />);

    const splitter = document.querySelector('.split-container__splitter');
    const container = screen.getByTestId('left-panel').closest('.split-container');

    // Try to drag to a very large size
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });
    fireEvent.mouseMove(document, { clientX: 750, clientY: 300 }); // Very large

    const splitSize = container.style.getPropertyValue('--split-size');
    const widthPercent = parseFloat(splitSize);

    // Should respect maximum size constraint
    expect(widthPercent).toBeLessThanOrEqual(90); // Should be clamped
  });

  it('calls onSplitChange when split changes', () => {
    const onSplitChange = jest.fn();
    render(<SplitContainer {...defaultProps} onSplitChange={onSplitChange} />);

    const splitter = document.querySelector('.split-container__splitter');

    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });
    fireEvent.mouseMove(document, { clientX: 300, clientY: 300 });

    expect(onSplitChange).toHaveBeenCalled();
  });

  it('applies custom className', () => {
    render(<SplitContainer {...defaultProps} className="custom-split" />);

    const container = screen.getByTestId('left-panel').closest('.split-container');
    expect(container).toHaveClass('custom-split');
  });

  it('handles vertical direction correctly', () => {
    render(<SplitContainer {...defaultProps} direction="vertical" />);

    const container = screen.getByTestId('left-panel').closest('.split-container');

    // In vertical mode, CSS custom properties are still used the same way
    expect(container.style.getPropertyValue('--split-size')).toBe('50%');
    expect(container.style.getPropertyValue('--remaining-size')).toBe('50%');
  });

  it('handles drag in vertical direction', () => {
    render(<SplitContainer {...defaultProps} direction="vertical" />);

    const splitter = document.querySelector('.split-container__splitter');
    const container = screen.getByTestId('left-panel').closest('.split-container');

    // Start vertical drag
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });
    fireEvent.mouseMove(document, { clientX: 400, clientY: 200 }); // Move vertically

    // Should update split position via CSS custom properties
    const splitSize = container.style.getPropertyValue('--split-size');
    expect(splitSize).toBeTruthy();
    expect(splitSize).toMatch(/^\d+(\.\d+)?%$/); // Should be a percentage
  });

  it('prevents text selection during drag', () => {
    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');

    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });

    // Should set document.onselectstart to prevent selection
    expect(document.onselectstart).toBeDefined();
    expect(document.onselectstart()).toBe(false);
  });

  it('cleans up event listeners on unmount', () => {
    const removeEventListenerSpy = jest.spyOn(document, 'removeEventListener');

    const { unmount } = render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });

    unmount();

    // Should clean up listeners
    expect(removeEventListenerSpy).toHaveBeenCalled();

    removeEventListenerSpy.mockRestore();
  });

  it('handles edge case with zero container size', () => {
    // Mock zero-size container
    Element.prototype.getBoundingClientRect = jest.fn(() => ({
      width: 0,
      height: 0,
      left: 0,
      top: 0,
      right: 0,
      bottom: 0
    }));

    render(<SplitContainer {...defaultProps} />);

    const splitter = document.querySelector('.split-container__splitter');

    // Should not crash with zero-size container
    fireEvent.mouseDown(splitter, { clientX: 400, clientY: 300 });
    fireEvent.mouseMove(document, { clientX: 300, clientY: 300 });

    expect(screen.getByTestId('left-panel')).toBeInTheDocument();
  });
});

