import { z } from "zod";
import { ContextScope, sleep } from "@reins/utils";
import { fireEvent, render, waitFor } from "@testing-library/react";

import { FormAdapter } from "utils";
import { Form } from "../form";

describe("Form [ Submitting ]", () => {
  const initialValues = {
    name: "name",
    email: "email",
    password: "password",
  };
  const form = new FormAdapter(initialValues);
  const formContexts = new ContextScope("Form").createContext("FormProvider", { form });

  const [FormProvider] = formContexts.getContext("FormProvider");

  const Provider = (props: Omit<Parameters<typeof FormProvider.Provider>[0], "__context">) => (
    <FormProvider.Provider {...props} __context={formContexts} />
  );
  const onSubmit = jest.fn();

  beforeEach(() => {
    form.reset();
    onSubmit.mockClear();
  });
  it("should submit Form with new values", async () => {
    const { getByTestId } = render(
      <Form formAdapter={form} Provider={Provider} onSubmit={onSubmit}>
        <button data-testid="submit" type="submit">
          Submit
        </button>
      </Form>,
    );
    const submit = getByTestId("submit");
    fireEvent.click(submit);

    form.setFieldValue("name", "new name");
    form.setFieldValue("email", "new email");
    form.setFieldValue("password", "new password");

    await waitFor(() => {
      expect(onSubmit).toHaveBeenCalledTimes(1);
      expect(onSubmit).toHaveBeenCalledWith({
        name: "new name",
        email: "new email",
        password: "new password",
      });
    });
  });
  it("should prevent submitting Form on validation errors", async () => {
    const { getByTestId } = render(
      <Form formAdapter={form} Provider={Provider} onSubmit={onSubmit}>
        <button data-testid="submit" type="submit">
          Submit
        </button>
      </Form>,
    );
    const submit = getByTestId("submit");

    form.setFieldValue("name", "new name");
    form.setFieldValue("email", "new email");
    form.setFieldValue("password", "new password");
    form.registerFieldValidation("email", { validate: z.string().email() });

    fireEvent.click(submit);

    await sleep(10);
    await waitFor(async () => {
      expect(onSubmit).toHaveBeenCalledTimes(0);
    });
  });
});
