import { fireEvent, render } from '@testing-library/react';
import * as Formik from 'formik';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { Link, MemoryRouter } from 'react-router-dom';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { SaveOnNavigate } from './SaveOnNavigate';

const submitFormSpy = vi.fn(() => Promise.resolve());

vi.mock('formik', () => ({
  useFormikContext: vi.fn(),
}));

const defaultFormikProps = {
  dirty: false,
  isValid: true,
  submitForm: submitFormSpy,
  values: 'true',
  isSubmitting: false,
} as any;

describe('SaveOnNavigate', () => {
  afterEach(() => {
    vi.clearAllMocks();
  });

  it('renders the component without crashing', async () => {
    vi.spyOn(Formik, 'useFormikContext').mockImplementation(
      () => defaultFormikProps,
    );

    const { container } = render(
      <MemoryRouter>
        <SaveOnNavigate isSubmitting={false} />
      </MemoryRouter>,
    );

    expect(container).toBeTruthy();
  });

  it(`form submission should be allowed if 'isSubmitting' is false`, async () => {
    const submitSpy = vi.fn(() => Promise.resolve());
    vi.spyOn(Formik, 'useFormikContext').mockImplementation(() => ({
      ...defaultFormikProps,
      submitForm: submitSpy,
      dirty: true,
      isSubmitting: false,
    }));

    const { container } = render(
      <MemoryRouter>
        <Link id="link" to="/test">
          link
        </Link>
        <SaveOnNavigate isSubmitting={false} />
      </MemoryRouter>,
    );

    const link = container.querySelector('a') as HTMLAnchorElement;
    fireEvent.click(link, { button: 0 });

    await act(async () => {
      // Wait for async operations
    });

    // assert submit was attempted
    expect(submitSpy).toHaveBeenCalledTimes(1);
  });

  it(`form submission should not be allowed if 'isSubmitting' is true`, async () => {
    const submitSpy = vi.fn(() => Promise.resolve());
    vi.spyOn(Formik, 'useFormikContext').mockImplementation(() => ({
      ...defaultFormikProps,
      submitForm: submitSpy,
      dirty: true,
      isSubmitting: false,
    }));

    const { container } = render(
      <MemoryRouter>
        <Link id="link" to="/test">
          link
        </Link>
        <SaveOnNavigate isSubmitting={true} />
      </MemoryRouter>,
    );

    const link = container.querySelector('a') as HTMLAnchorElement;
    fireEvent.click(link, { button: 0 });

    await act(async () => {
      // Wait for async operations
    });

    // assert another submit was not attempted
    expect(submitSpy).toHaveBeenCalledTimes(0);
  });
});
