/**
 * Unit tests for ChartWidget component
 *
 * Tests cover:
 * - Chart container rendering
 * - Title display
 * - Bar chart rendering
 * - Line chart rendering
 * - Data visualization
 * - Custom colors
 * - Value prefixes
 * - Edit mode with drag handle and remove button
 * - Tooltip formatting
 * - Responsive container
 * - Accessibility
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import ChartWidget from '../ChartWidget';

// Mock Recharts components to avoid rendering issues in tests
vi.mock('recharts', () => ({
  ResponsiveContainer: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="responsive-container">{children}</div>
  ),
  BarChart: ({ data, children }: { data: any[]; children: React.ReactNode }) => (
    <div data-testid="bar-chart" data-chart-data={JSON.stringify(data)}>
      {children}
    </div>
  ),
  LineChart: ({ data, children }: { data: any[]; children: React.ReactNode }) => (
    <div data-testid="line-chart" data-chart-data={JSON.stringify(data)}>
      {children}
    </div>
  ),
  Bar: ({ dataKey, fill }: { dataKey: string; fill: string }) => (
    <div data-testid="bar" data-key={dataKey} data-fill={fill} />
  ),
  Line: ({ dataKey, stroke }: { dataKey: string; stroke: string }) => (
    <div data-testid="line" data-key={dataKey} data-stroke={stroke} />
  ),
  XAxis: ({ dataKey }: { dataKey: string }) => (
    <div data-testid="x-axis" data-key={dataKey} />
  ),
  YAxis: () => <div data-testid="y-axis" />,
  CartesianGrid: () => <div data-testid="cartesian-grid" />,
  Tooltip: () => <div data-testid="tooltip" />,
}));

describe('ChartWidget', () => {
  const mockChartData = [
    { name: 'Mon', value: 100 },
    { name: 'Tue', value: 150 },
    { name: 'Wed', value: 120 },
    { name: 'Thu', value: 180 },
    { name: 'Fri', value: 200 },
  ];

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

  describe('Rendering', () => {
    it('should render the component', () => {
      render(
        <ChartWidget
          title="Revenue Chart"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByText('Revenue Chart')).toBeInTheDocument();
    });

    it('should render chart container', () => {
      render(
        <ChartWidget
          title="Revenue Chart"
          data={mockChartData}
          type="bar"
        />
      );

      const container = screen.getByTestId('responsive-container');
      expect(container).toBeInTheDocument();
    });

    it('should render with different titles', () => {
      const { rerender } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByText('Revenue')).toBeInTheDocument();

      rerender(
        <ChartWidget
          title="Appointments"
          data={mockChartData}
          type="bar"
        />
      );

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

    it('should render with empty data array', () => {
      render(
        <ChartWidget
          title="Empty Chart"
          data={[]}
          type="bar"
        />
      );

      expect(screen.getByText('Empty Chart')).toBeInTheDocument();
      expect(screen.getByTestId('bar-chart')).toBeInTheDocument();
    });
  });

  describe('Title', () => {
    it('should display title with correct styling', () => {
      render(
        <ChartWidget
          title="Weekly Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const title = screen.getByText('Weekly Revenue');
      expect(title).toBeInTheDocument();
      expect(title).toHaveClass('text-lg', 'font-semibold', 'text-gray-900');
    });

    it('should apply dark mode styles to title', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const title = screen.getByText('Revenue');
      expect(title).toHaveClass('dark:text-white');
    });

    it('should handle long titles', () => {
      const longTitle = 'Very Long Chart Title That Should Still Display Properly Without Breaking Layout';
      render(
        <ChartWidget
          title={longTitle}
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByText(longTitle)).toBeInTheDocument();
    });
  });

  describe('Bar Chart', () => {
    it('should render bar chart when type is "bar"', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByTestId('bar-chart')).toBeInTheDocument();
      expect(screen.queryByTestId('line-chart')).not.toBeInTheDocument();
    });

    it('should pass data to bar chart', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const barChart = screen.getByTestId('bar-chart');
      const chartData = JSON.parse(barChart.getAttribute('data-chart-data') || '[]');
      expect(chartData).toEqual(mockChartData);
    });

    it('should render bar with correct dataKey', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const bar = screen.getByTestId('bar');
      expect(bar).toHaveAttribute('data-key', 'value');
    });

    it('should render bar with default color', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const bar = screen.getByTestId('bar');
      expect(bar).toHaveAttribute('data-fill', '#3b82f6');
    });

    it('should render bar with custom color', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          color="#10b981"
        />
      );

      const bar = screen.getByTestId('bar');
      expect(bar).toHaveAttribute('data-fill', '#10b981');
    });

    it('should render CartesianGrid for bar chart', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByTestId('cartesian-grid')).toBeInTheDocument();
    });

    it('should render XAxis with name dataKey', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const xAxis = screen.getByTestId('x-axis');
      expect(xAxis).toHaveAttribute('data-key', 'name');
    });

    it('should render YAxis', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByTestId('y-axis')).toBeInTheDocument();
    });

    it('should render Tooltip', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByTestId('tooltip')).toBeInTheDocument();
    });
  });

  describe('Line Chart', () => {
    it('should render line chart when type is "line"', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
        />
      );

      expect(screen.getByTestId('line-chart')).toBeInTheDocument();
      expect(screen.queryByTestId('bar-chart')).not.toBeInTheDocument();
    });

    it('should pass data to line chart', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
        />
      );

      const lineChart = screen.getByTestId('line-chart');
      const chartData = JSON.parse(lineChart.getAttribute('data-chart-data') || '[]');
      expect(chartData).toEqual(mockChartData);
    });

    it('should render line with correct dataKey', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
        />
      );

      const line = screen.getByTestId('line');
      expect(line).toHaveAttribute('data-key', 'value');
    });

    it('should render line with default color', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
        />
      );

      const line = screen.getByTestId('line');
      expect(line).toHaveAttribute('data-stroke', '#3b82f6');
    });

    it('should render line with custom color', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
          color="#ef4444"
        />
      );

      const line = screen.getByTestId('line');
      expect(line).toHaveAttribute('data-stroke', '#ef4444');
    });

    it('should render CartesianGrid for line chart', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
        />
      );

      expect(screen.getByTestId('cartesian-grid')).toBeInTheDocument();
    });

    it('should switch between chart types', () => {
      const { rerender } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByTestId('bar-chart')).toBeInTheDocument();

      rerender(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="line"
        />
      );

      expect(screen.getByTestId('line-chart')).toBeInTheDocument();
      expect(screen.queryByTestId('bar-chart')).not.toBeInTheDocument();
    });
  });

  describe('Value Prefix', () => {
    it('should use empty prefix by default', () => {
      render(
        <ChartWidget
          title="Appointments"
          data={mockChartData}
          type="bar"
        />
      );

      // Component renders successfully without prefix
      expect(screen.getByText('Appointments')).toBeInTheDocument();
    });

    it('should accept custom value prefix', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          valuePrefix="$"
        />
      );

      // Component renders successfully with prefix
      expect(screen.getByText('Revenue')).toBeInTheDocument();
    });

    it('should accept different prefixes', () => {
      const { rerender } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          valuePrefix="$"
        />
      );

      expect(screen.getByText('Revenue')).toBeInTheDocument();

      rerender(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          valuePrefix="€"
        />
      );

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

  describe('Edit Mode', () => {
    it('should not show edit controls when isEditing is false', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={false}
        />
      );

      const dragHandle = container.querySelector('.drag-handle');
      expect(dragHandle).not.toBeInTheDocument();
    });

    it('should show drag handle when in edit mode', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={true}
        />
      );

      const dragHandle = container.querySelector('.drag-handle');
      expect(dragHandle).toBeInTheDocument();
    });

    it('should show remove button when in edit mode', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={true}
          onRemove={vi.fn()}
        />
      );

      const removeButton = screen.getByRole('button');
      expect(removeButton).toBeInTheDocument();
    });

    it('should call onRemove when remove button is clicked', async () => {
      const user = userEvent.setup();
      const handleRemove = vi.fn();

      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={true}
          onRemove={handleRemove}
        />
      );

      const removeButton = screen.getByRole('button');
      await user.click(removeButton);

      expect(handleRemove).toHaveBeenCalledTimes(1);
    });

    it('should apply padding to title when in edit mode', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={true}
        />
      );

      const title = screen.getByText('Revenue');
      expect(title).toHaveClass('pl-5');
    });

    it('should not apply padding to title when not in edit mode', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={false}
        />
      );

      const title = screen.getByText('Revenue');
      expect(title).not.toHaveClass('pl-5');
    });

    it('should have grab cursor on drag handle', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={true}
        />
      );

      const dragHandle = container.querySelector('.drag-handle');
      expect(dragHandle).toHaveClass('cursor-grab', 'active:cursor-grabbing');
    });
  });

  describe('Responsive Container', () => {
    it('should render ResponsiveContainer', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByTestId('responsive-container')).toBeInTheDocument();
    });

    it('should wrap chart in responsive container', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const container = screen.getByTestId('responsive-container');
      const barChart = screen.getByTestId('bar-chart');

      expect(container).toContainElement(barChart);
    });

    it('should have flex layout for proper sizing', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const widget = container.firstChild;
      expect(widget).toHaveClass('flex', 'flex-col');
    });
  });

  describe('Styling', () => {
    it('should apply container styles', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const widget = container.firstChild;
      expect(widget).toHaveClass(
        'h-full',
        'p-4',
        'bg-white',
        'rounded-xl',
        'border',
        'border-gray-200',
        'shadow-sm',
        'relative',
        'group'
      );
    });

    it('should apply dark mode styles', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const widget = container.firstChild;
      expect(widget).toHaveClass('dark:bg-gray-800', 'dark:border-gray-700');
    });

    it('should have proper spacing for title', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const title = screen.getByText('Revenue');
      expect(title).toHaveClass('mb-4');
    });

    it('should use flex-1 for chart container', () => {
      const { container } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const chartContainer = container.querySelector('.flex-1');
      expect(chartContainer).toBeInTheDocument();
      expect(chartContainer).toHaveClass('min-h-0');
    });
  });

  describe('Data Handling', () => {
    it('should handle single data point', () => {
      const singlePoint = [{ name: 'Mon', value: 100 }];

      render(
        <ChartWidget
          title="Revenue"
          data={singlePoint}
          type="bar"
        />
      );

      const barChart = screen.getByTestId('bar-chart');
      const chartData = JSON.parse(barChart.getAttribute('data-chart-data') || '[]');
      expect(chartData).toEqual(singlePoint);
    });

    it('should handle large datasets', () => {
      const largeData = Array.from({ length: 100 }, (_, i) => ({
        name: `Day ${i + 1}`,
        value: Math.random() * 1000,
      }));

      render(
        <ChartWidget
          title="Revenue"
          data={largeData}
          type="line"
        />
      );

      const lineChart = screen.getByTestId('line-chart');
      const chartData = JSON.parse(lineChart.getAttribute('data-chart-data') || '[]');
      expect(chartData).toHaveLength(100);
    });

    it('should handle zero values', () => {
      const zeroData = [
        { name: 'Mon', value: 0 },
        { name: 'Tue', value: 0 },
      ];

      render(
        <ChartWidget
          title="Revenue"
          data={zeroData}
          type="bar"
        />
      );

      const barChart = screen.getByTestId('bar-chart');
      const chartData = JSON.parse(barChart.getAttribute('data-chart-data') || '[]');
      expect(chartData).toEqual(zeroData);
    });

    it('should handle negative values', () => {
      const negativeData = [
        { name: 'Mon', value: -50 },
        { name: 'Tue', value: 100 },
        { name: 'Wed', value: -30 },
      ];

      render(
        <ChartWidget
          title="Profit/Loss"
          data={negativeData}
          type="line"
        />
      );

      const lineChart = screen.getByTestId('line-chart');
      const chartData = JSON.parse(lineChart.getAttribute('data-chart-data') || '[]');
      expect(chartData).toEqual(negativeData);
    });
  });

  describe('Accessibility', () => {
    it('should have semantic heading for title', () => {
      render(
        <ChartWidget
          title="Revenue Chart"
          data={mockChartData}
          type="bar"
        />
      );

      const heading = screen.getByRole('heading', { level: 3 });
      expect(heading).toHaveTextContent('Revenue Chart');
    });

    it('should be keyboard accessible in edit mode', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          isEditing={true}
          onRemove={vi.fn()}
        />
      );

      const button = screen.getByRole('button');
      expect(button).toBeInTheDocument();
    });

    it('should have proper color contrast', () => {
      render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
        />
      );

      const title = screen.getByText('Revenue');
      expect(title).toHaveClass('text-gray-900');
    });
  });

  describe('Integration', () => {
    it('should render correctly with all props', () => {
      const handleRemove = vi.fn();

      render(
        <ChartWidget
          title="Weekly Revenue"
          data={mockChartData}
          type="bar"
          color="#10b981"
          valuePrefix="$"
          isEditing={true}
          onRemove={handleRemove}
        />
      );

      expect(screen.getByText('Weekly Revenue')).toBeInTheDocument();
      expect(screen.getByTestId('bar-chart')).toBeInTheDocument();
      expect(screen.getByTestId('bar')).toHaveAttribute('data-fill', '#10b981');
      expect(screen.getByRole('button')).toBeInTheDocument();
    });

    it('should work with minimal props', () => {
      render(
        <ChartWidget
          title="Simple Chart"
          data={mockChartData}
          type="bar"
        />
      );

      expect(screen.getByText('Simple Chart')).toBeInTheDocument();
      expect(screen.getByTestId('bar-chart')).toBeInTheDocument();
    });

    it('should maintain layout with varying data lengths', () => {
      const shortData = [{ name: 'A', value: 1 }];
      const { rerender } = render(
        <ChartWidget
          title="Data"
          data={shortData}
          type="bar"
        />
      );

      expect(screen.getByText('Data')).toBeInTheDocument();

      const longData = Array.from({ length: 50 }, (_, i) => ({
        name: `Item ${i}`,
        value: i * 10,
      }));

      rerender(
        <ChartWidget
          title="Data"
          data={longData}
          type="bar"
        />
      );

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

    it('should support different color schemes', () => {
      const colors = ['#3b82f6', '#10b981', '#ef4444', '#f59e0b', '#8b5cf6'];

      const { rerender } = render(
        <ChartWidget
          title="Revenue"
          data={mockChartData}
          type="bar"
          color={colors[0]}
        />
      );

      colors.forEach((color) => {
        rerender(
          <ChartWidget
            title="Revenue"
            data={mockChartData}
            type="bar"
            color={color}
          />
        );

        const bar = screen.getByTestId('bar');
        expect(bar).toHaveAttribute('data-fill', color);
      });
    });

    it('should handle rapid data updates', () => {
      const { rerender } = render(
        <ChartWidget
          title="Live Data"
          data={mockChartData}
          type="line"
        />
      );

      for (let i = 0; i < 10; i++) {
        const newData = mockChartData.map((item) => ({
          ...item,
          value: item.value + Math.random() * 50,
        }));

        rerender(
          <ChartWidget
            title="Live Data"
            data={newData}
            type="line"
          />
        );

        expect(screen.getByText('Live Data')).toBeInTheDocument();
      }
    });
  });
});
