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

describe('DatePicker Component', () => {
  const mockOnChange = vi.fn();

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

  it('renders date picker trigger correctly', () => {
    render(<DatePicker onChange={mockOnChange} />);

    expect(screen.getByText('Select date...')).toBeInTheDocument();
  });

  it('uses custom placeholder', () => {
    render(<DatePicker onChange={mockOnChange} placeholder="Choose a date" />);

    expect(screen.getByText('Choose a date')).toBeInTheDocument();
  });

  it('displays selected date in single mode', () => {
    const date = new Date(2024, 0, 15);
    render(<DatePicker value={date} onChange={mockOnChange} mode="single" />);

    expect(screen.getByText(date.toLocaleDateString())).toBeInTheDocument();
  });

  it('displays selected date range', () => {
    const start = new Date(2024, 0, 15);
    const end = new Date(2024, 0, 20);
    render(
      <DatePicker
        value={{ start, end }}
        onChange={mockOnChange}
        mode="range"
      />,
    );

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const displayText = `${start.toLocaleDateString()} - ${end.toLocaleDateString()}`;
    expect(
      screen.getByText(
        new RegExp(start.toLocaleDateString().replace(/\//g, '/')),
      ),
    ).toBeInTheDocument();
  });

  it('opens calendar when trigger is clicked', async () => {
    const user = userEvent.setup();
    render(<DatePicker onChange={mockOnChange} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });
  });

  it('displays current month by default', async () => {
    const user = userEvent.setup();
    const now = new Date();
    render(<DatePicker onChange={mockOnChange} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      const monthNames = [
        'January',
        'February',
        'March',
        'April',
        'May',
        'June',
        'July',
        'August',
        'September',
        'October',
        'November',
        'December',
      ];
      const monthText = `${monthNames[now.getMonth()]} ${now.getFullYear()}`;
      expect(screen.getByText(monthText)).toBeInTheDocument();
    });
  });

  it('navigates to previous month', async () => {
    const user = userEvent.setup();
    const now = new Date();
    const prevMonth = now.getMonth() === 0 ? 11 : now.getMonth() - 1;
    const prevYear =
      now.getMonth() === 0 ? now.getFullYear() - 1 : now.getFullYear();

    render(<DatePicker onChange={mockOnChange} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    const prevButton = screen.getAllByRole('button').find((btn) => {
      const svg = btn.querySelector('svg');
      return svg && svg.getAttribute('d')?.includes('m15 18-6-6 6-6');
    });

    if (prevButton) {
      await user.click(prevButton);

      await waitFor(() => {
        const monthNames = [
          'January',
          'February',
          'March',
          'April',
          'May',
          'June',
          'July',
          'August',
          'September',
          'October',
          'November',
          'December',
        ];
        const monthText = `${monthNames[prevMonth]} ${prevYear}`;
        expect(screen.getByText(monthText)).toBeInTheDocument();
      });
    }
  });

  it('navigates to next month', async () => {
    const user = userEvent.setup();
    const now = new Date();
    const nextMonth = now.getMonth() === 11 ? 0 : now.getMonth() + 1;
    const nextYear =
      now.getMonth() === 11 ? now.getFullYear() + 1 : now.getFullYear();

    render(<DatePicker onChange={mockOnChange} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    const nextButtons = screen.getAllByRole('button');
    const nextButton = nextButtons.find((btn) => {
      const svg = btn.querySelector('svg');
      return svg && btn.getAttribute('aria-label') !== 'Fermer';
    });

    // Chercher le bouton avec ChevronRight
    const chevronRightButtons = Array.from(
      document.querySelectorAll('svg'),
    ).filter((svg) => {
      const path = svg.querySelector('path');
      return path && path.getAttribute('d')?.includes('m9 18 6-6-6-6');
    });

    if (chevronRightButtons.length > 0) {
      const nextBtn = chevronRightButtons[0].closest('button');
      if (nextBtn) {
        await user.click(nextBtn);

        await waitFor(() => {
          const monthNames = [
            'January',
            'February',
            'March',
            'April',
            'May',
            'June',
            'July',
            'August',
            'September',
            'October',
            'November',
            'December',
          ];
          const monthText = `${monthNames[nextMonth]} ${nextYear}`;
          expect(screen.getByText(monthText)).toBeInTheDocument();
        });
      }
    }
  });

  it('selects a date in single mode', async () => {
    const user = userEvent.setup();
    render(<DatePicker onChange={mockOnChange} mode="single" />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    // Sélectionner le jour 15
    const day15 = screen.getByText('15');
    if (day15) {
      await user.click(day15);
      expect(mockOnChange).toHaveBeenCalled();
      const selectedDate = mockOnChange.mock.calls[0][0];
      expect(selectedDate).toBeInstanceOf(Date);
    }
  });

  it('selects date range', async () => {
    const user = userEvent.setup();
    render(<DatePicker onChange={mockOnChange} mode="range" />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) =>
        btn.textContent?.includes('Select date range...'),
      ) || triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    // Sélectionner le jour 15
    const day15 = screen.getByText('15');
    if (day15) {
      await user.click(day15);
      expect(mockOnChange).toHaveBeenCalled();
      const firstCall = mockOnChange.mock.calls[0][0];
      expect(firstCall).toHaveProperty('start');
      expect(firstCall).toHaveProperty('end');
    }
  });

  it('completes date range selection', async () => {
    const user = userEvent.setup();
    const startDate = new Date(2024, 0, 15);
    render(
      <DatePicker
        value={{ start: startDate, end: startDate }}
        onChange={mockOnChange}
        mode="range"
      />,
    );

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('15')) || triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    // Sélectionner le jour 20 pour compléter la range
    const day20 = screen.getByText('20');
    if (day20) {
      await user.click(day20);
      expect(mockOnChange).toHaveBeenCalled();
      const call =
        mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1][0];
      expect(call).toHaveProperty('start');
      expect(call).toHaveProperty('end');
      expect(call.start).toBeInstanceOf(Date);
      expect(call.end).toBeInstanceOf(Date);
    }
  });

  it('disables dates before minDate', async () => {
    const user = userEvent.setup();
    const minDate = new Date(2024, 0, 15);
    render(<DatePicker onChange={mockOnChange} minDate={minDate} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    // Le jour 1 devrait être désactivé (avant le 15)
    const day1 = screen.queryByText('1');
    if (day1) {
      const dayButton = day1.closest('button');
      // Vérifier que le bouton est désactivé ou a les classes de désactivation
      expect(
        dayButton?.classList.contains('opacity-50') ||
          dayButton?.classList.contains('cursor-not-allowed') ||
          dayButton?.hasAttribute('disabled'),
      ).toBe(true);
    }
  });

  it('disables dates after maxDate', async () => {
    const user = userEvent.setup();
    const maxDate = new Date(2024, 0, 15);
    render(<DatePicker onChange={mockOnChange} maxDate={maxDate} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    // Le jour 31 devrait être désactivé si après maxDate
    const day31 = screen.queryByText('31');
    if (day31) {
      const dayButton = day31.closest('button');
      if (dayButton) {
        expect(dayButton).toHaveClass('opacity-50');
      }
    }
  });

  it('clears selection when clear button is clicked', async () => {
    const user = userEvent.setup();
    const date = new Date(2024, 0, 15);
    render(<DatePicker value={date} onChange={mockOnChange} mode="single" />);

    const triggers = screen.getAllByRole('button');
    const trigger = triggers.find((btn) => btn.textContent?.includes('15'));
    const clearButton = trigger?.querySelector('svg');

    if (clearButton) {
      await user.click(clearButton);
      await waitFor(() => {
        expect(mockOnChange).toHaveBeenCalled();
      });
      // Vérifier que onChange a été appelé avec undefined ou null
      const lastCall =
        mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1];
      expect(lastCall[0] === undefined || lastCall[0] === null).toBe(true);
    }
  });

  it('selects today when Today button is clicked', async () => {
    const user = userEvent.setup();
    render(<DatePicker onChange={mockOnChange} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Today')).toBeInTheDocument();
    });

    const todayButton = screen.getByText('Today');
    await user.click(todayButton);

    expect(mockOnChange).toHaveBeenCalled();
    const selectedDate = mockOnChange.mock.calls[0][0];
    expect(selectedDate).toBeInstanceOf(Date);
  });

  it('disables date picker when disabled prop is true', () => {
    render(<DatePicker onChange={mockOnChange} disabled />);

    const buttons = document.querySelectorAll('button');
    const selectButton = Array.from(buttons).find(
      (btn) => btn.textContent?.includes('Select date...') && btn.disabled,
    );
    expect(selectButton).toBeInTheDocument();
  });

  it('displays days of week correctly', async () => {
    const user = userEvent.setup();
    render(<DatePicker onChange={mockOnChange} />);

    const triggers = screen.getAllByRole('button');
    const trigger =
      triggers.find((btn) => btn.textContent?.includes('Select date...')) ||
      triggers[0];
    await user.click(trigger);

    await waitFor(() => {
      expect(screen.getByText('Mon')).toBeInTheDocument();
      expect(screen.getByText('Tue')).toBeInTheDocument();
      expect(screen.getByText('Wed')).toBeInTheDocument();
      expect(screen.getByText('Thu')).toBeInTheDocument();
      expect(screen.getByText('Fri')).toBeInTheDocument();
      expect(screen.getByText('Sat')).toBeInTheDocument();
      expect(screen.getByText('Sun')).toBeInTheDocument();
    });
  });
});
