import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { Timeline, TimelineItem } from './Timeline';
import { Calendar, CheckCircle } from 'lucide-react';

describe('Timeline Component', () => {
  const mockItems: TimelineItem[] = [
    {
      id: '1',
      title: 'Événement 1',
      description: "Description de l'événement 1",
      date: new Date('2024-01-01'),
    },
    {
      id: '2',
      title: 'Événement 2',
      description: "Description de l'événement 2",
      date: new Date('2024-01-15'),
    },
    {
      id: '3',
      title: 'Événement 3',
      date: new Date('2024-02-01'),
    },
  ];

  describe('Rendering', () => {
    it('renders timeline with items', () => {
      render(<Timeline items={mockItems} />);

      expect(screen.getByText('Événement 1')).toBeInTheDocument();
      expect(screen.getByText('Événement 2')).toBeInTheDocument();
      expect(screen.getByText('Événement 3')).toBeInTheDocument();
    });

    it('renders empty message when items is empty', () => {
      render(<Timeline items={[]} />);

      expect(
        screen.getByText('Aucun événement à afficher'),
      ).toBeInTheDocument();
    });

    it('renders descriptions when provided', () => {
      render(<Timeline items={mockItems} />);

      expect(
        screen.getByText("Description de l'événement 1"),
      ).toBeInTheDocument();
      expect(
        screen.getByText("Description de l'événement 2"),
      ).toBeInTheDocument();
    });

    it('does not render description when not provided', () => {
      render(<Timeline items={mockItems} />);

      const event3 = screen.getByText('Événement 3').closest('div');
      expect(event3).toBeInTheDocument();
      // L'événement 3 n'a pas de description
    });

    it('renders dates', () => {
      render(<Timeline items={mockItems} />);

      // Les dates sont formatées, on vérifie qu'elles sont présentes
      const date1 = formatDate(mockItems[0].date, 'short');
      expect(screen.getByText(date1)).toBeInTheDocument();
    });

    it('renders dates with string format', () => {
      const itemsWithStringDates: TimelineItem[] = [
        {
          id: '1',
          title: 'Événement',
          date: '2024-01-01',
        },
      ];

      render(<Timeline items={itemsWithStringDates} />);

      const date = formatDate(itemsWithStringDates[0].date, 'short');
      expect(screen.getByText(date)).toBeInTheDocument();
    });
  });

  describe('Icons', () => {
    it('renders custom icon when provided', () => {
      const itemsWithIcon: TimelineItem[] = [
        {
          id: '1',
          title: 'Événement avec icône',
          date: new Date('2024-01-01'),
          icon: <Calendar data-testid="calendar-icon" />,
        },
      ];

      render(<Timeline items={itemsWithIcon} />);

      expect(screen.getByTestId('calendar-icon')).toBeInTheDocument();
    });

    it('renders default dot when icon is not provided', () => {
      render(<Timeline items={mockItems} />);

      // Vérifier que les icônes par défaut sont présentes (3 items = 3 dots)
      const icons = document.querySelectorAll('.h-2.w-2');
      expect(icons.length).toBe(3);
    });

    it('renders multiple icons correctly', () => {
      const itemsWithMultipleIcons: TimelineItem[] = [
        {
          id: '1',
          title: 'Événement 1',
          date: new Date('2024-01-01'),
          icon: <Calendar data-testid="icon-1" />,
        },
        {
          id: '2',
          title: 'Événement 2',
          date: new Date('2024-01-15'),
          icon: <CheckCircle data-testid="icon-2" />,
        },
        {
          id: '3',
          title: 'Événement 3',
          date: new Date('2024-02-01'),
        },
      ];

      render(<Timeline items={itemsWithMultipleIcons} />);

      expect(screen.getByTestId('icon-1')).toBeInTheDocument();
      expect(screen.getByTestId('icon-2')).toBeInTheDocument();
    });
  });

  describe('Orientation', () => {
    it('renders vertical timeline by default', () => {
      const { container } = render(<Timeline items={mockItems} />);

      // Vérifier que la structure verticale est présente
      const timeline = container.firstChild;
      expect(timeline).toBeInTheDocument();
      // Les lignes verticales doivent être présentes
      const verticalLines = container.querySelectorAll('.h-full.w-0\\.5');
      expect(verticalLines.length).toBeGreaterThan(0);
    });

    it('renders horizontal timeline when orientation is horizontal', () => {
      const { container } = render(
        <Timeline items={mockItems} orientation="horizontal" />,
      );

      // Vérifier que la structure horizontale est présente
      const timeline = container.firstChild;
      expect(timeline).toBeInTheDocument();
      // Les lignes horizontales doivent être présentes
      const horizontalLines = container.querySelectorAll('.h-0\\.5');
      expect(horizontalLines.length).toBeGreaterThan(0);
    });

    it('applies correct classes for horizontal orientation', () => {
      const { container } = render(
        <Timeline items={mockItems} orientation="horizontal" />,
      );

      const flexContainer = container.querySelector('.flex.items-start');
      expect(flexContainer).toBeInTheDocument();
    });
  });

  describe('Connecting Lines', () => {
    it('renders connecting lines between items in vertical orientation', () => {
      const { container } = render(<Timeline items={mockItems} />);

      // Il devrait y avoir 2 lignes de connexion pour 3 items (n-1)
      const verticalLines = container.querySelectorAll(
        '.h-full.w-0\\.5.bg-border',
      );
      expect(verticalLines.length).toBe(2);
    });

    it('renders connecting lines between items in horizontal orientation', () => {
      const { container } = render(
        <Timeline items={mockItems} orientation="horizontal" />,
      );

      // Il devrait y avoir 2 lignes de connexion pour 3 items (n-1)
      const horizontalLines = container.querySelectorAll('.h-0\\.5.bg-border');
      expect(horizontalLines.length).toBe(2);
    });

    it('does not render connecting line for single item', () => {
      const singleItem: TimelineItem[] = [
        {
          id: '1',
          title: 'Seul événement',
          date: new Date('2024-01-01'),
        },
      ];

      const { container } = render(<Timeline items={singleItem} />);

      const lines = container.querySelectorAll('.bg-border');
      expect(lines.length).toBe(0);
    });

    it('does not render connecting line after last item', () => {
      const { container } = render(<Timeline items={mockItems} />);

      // Vérifier que le dernier item n'a pas de ligne après lui
      const allLines = container.querySelectorAll('.bg-border');
      expect(allLines.length).toBe(2); // Seulement 2 lignes pour 3 items
    });
  });

  describe('Custom className', () => {
    it('applies custom className', () => {
      const { container } = render(
        <Timeline items={mockItems} className="custom-timeline" />,
      );

      const timeline = container.firstChild;
      expect(timeline).toHaveClass('custom-timeline');
    });
  });

  describe('Accessibility', () => {
    it('renders items with proper structure', () => {
      render(<Timeline items={mockItems} />);

      // Vérifier que chaque item a un titre
      expect(screen.getByText('Événement 1')).toBeInTheDocument();
      expect(screen.getByText('Événement 2')).toBeInTheDocument();
      expect(screen.getByText('Événement 3')).toBeInTheDocument();
    });

    it('maintains item order', () => {
      const { container } = render(<Timeline items={mockItems} />);

      const items = container.querySelectorAll('[class*="flex"]');
      expect(items.length).toBeGreaterThan(0);
    });
  });
});

// Helper function pour formater les dates (copie de l'utilitaire)
function formatDate(
  date: Date | string,
  format: 'short' | 'long' | 'relative' = 'short',
): string {
  const d = new Date(date);

  if (isNaN(d.getTime())) {
    return 'Invalid date';
  }

  switch (format) {
    case 'short':
      return d.toLocaleDateString();
    case 'long':
      return d.toLocaleDateString('fr-FR', {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
        hour: '2-digit',
        minute: '2-digit',
      });
    case 'relative':
      return 'relative';
    default:
      return d.toLocaleDateString();
  }
}
