import { fireEvent, render, waitFor } from '@testing-library/react';
import { DateTime, Settings } from 'luxon';
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { noop } from '../../../../helpers/utils';
import { DateTimeFilter } from './DateTimeFilter';

// Mock dependencies
vi.mock('../../../../hooks', () => ({
  useClickOutside: vi.fn(),
}));

vi.mock('react-popper', () => ({
  usePopper: vi.fn(() => ({
    styles: { popper: {} },
    attributes: { popper: {} },
  })),
}));

vi.mock('react-dom', async () => ({
  ...(await vi.importActual('react-dom')),
  createPortal: (node: React.ReactNode) => node,
}));

describe('DateTimeFilter', () => {
  Settings.defaultLocale = navigator.language;

  it('Filter input is rendered', () => {
    const { container } = render(
      <DateTimeFilter onSelect={noop} modifyTime={true} />,
    );
    expect(container.querySelector('.inputValue')).toBeInTheDocument();
  });

  it('returns date string if value can be parsed', () => {
    const spy = vi.fn();
    const { container } = render(
      <DateTimeFilter onSelect={spy} modifyTime={true} />,
    );
    const date = DateTime.local().set({ second: 0, millisecond: 0 });
    const input = container.querySelector('.inputValue') as HTMLInputElement;

    fireEvent.change(input, {
      target: { value: date.toISO() },
    });

    fireEvent.keyDown(input, {
      key: 'Enter',
    });

    expect(spy).toHaveBeenCalledWith(date.toISO());
  });

  it('displays an error if value cannot be parsed', () => {
    const spy = vi.fn();
    const { container } = render(
      <DateTimeFilter onSelect={spy} modifyTime={true} />,
    );
    const input = container.querySelector('.inputValue') as HTMLInputElement;

    fireEvent.change(input, {
      target: { value: 'sampleText' },
    });

    fireEvent.keyDown(input, {
      key: 'Enter',
    });

    expect(spy).toHaveBeenCalledTimes(0);

    const error = container.querySelector('small');

    expect(error).toBeDefined();
  });

  it('displays the date time picker when the button is clicked', async () => {
    const spy = vi.fn();
    const date = DateTime.local().set({ second: 0, millisecond: 0 });
    const { container } = render(
      <DateTimeFilter onSelect={spy} modifyTime={true} />,
    );

    const button = container.querySelector('button') as HTMLButtonElement;

    fireEvent.click(button);

    // Date picker may be rendered in a portal to document.body
    const datePicker = await waitFor(() => {
      const el = document.querySelector('.date-time-picker-container');
      expect(el).toBeInTheDocument();
      return el;
    });

    // Note: Testing nested component callbacks is challenging in RTL
    // This test verifies the date picker appears when button is clicked
  });

  it('Executes validator and displays message', () => {
    const spy = vi.fn();
    const { container } = render(
      <DateTimeFilter
        onSelect={spy}
        modifyTime={true}
        onValidate={() => 'invalid'}
      />,
    );
    const date = DateTime.local().set({ second: 0, millisecond: 0 });
    const input = container.querySelector('.inputValue') as HTMLInputElement;

    fireEvent.change(input, {
      target: { value: date.toISO() },
    });

    fireEvent.keyDown(input, {
      key: 'Enter',
    });

    expect(spy).toHaveBeenCalledTimes(0);

    const error = container.querySelector('small');

    expect(error).toBeDefined();
  });
});
