import { FormInputLayout } from "@/components/form-common/form-layouts";
import { Input } from "@/components/ui/input";
import { handleFormElementSubmitEvent } from "@/lib/form";
import { enableActx, useActx } from "@/testutils/use-actx";
import { FormApi, useForm } from "@tanstack/react-form";
import { fireEvent, render } from "@testing-library/react";
import { createRef, type Ref, useImperativeHandle } from "react";
import { expect, suite, test } from "vitest";
import { z } from "zod";
import { FormSubmit } from "./form-submit";

enableActx();

suite("FormSubmit", () => {
  test("<FormSubmit />", async () => {
    const actx = useActx();

    const ref =
      createRef<
        FormApi<any, any, any, any, any, any, any, any, any, any, any, any>
      >();
    const ui = render(<TestingFormComponent ref={ref} />);

    const input = ui.queryByRole("textbox") as HTMLInputElement;
    const submitButton = ui.queryByRole("button", {
      name: "Submit",
    }) as HTMLButtonElement;

    expect(submitButton.disabled).toBe(false);

    // Click without any validation result
    await actx(() => {
      submitButton.click();
    });
    expect(submitButton.disabled).toBe(true);
    expect(ref.current?.state.isSubmitting).toBe(false);

    // Update input to invalid value
    await actx(() => {
      fireEvent.change(input, { target: { value: "invalid" } });
      fireEvent.blur(input, { target: {} });
    });
    expect(input.value).toBe("invalid");
    expect(submitButton.disabled).toBe(true);

    // Update input to valid value
    await actx(() => {
      fireEvent.change(input, { target: { value: "valid" } });
      fireEvent.blur(input, { target: {} });
    });
    expect(input.value).toBe("valid");
    expect(submitButton.disabled).toBe(false);

    // Successfully submitted
    await actx(() => {
      submitButton.click();
    });
    expect(ref.current?.state.isSubmitting).toBe(false);
    expect(ref.current?.state?.isSubmitSuccessful).toBe(true);
    expect(submitButton.disabled).toBe(false);
  });
});

function TestingFormComponent({
  ref,
}: {
  ref: Ref<FormApi<any, any, any, any, any, any, any, any, any, any, any, any>>;
}) {
  const schema = z.object({
    foo: z.string().regex(/^valid$/),
  });
  const form = useForm({
    validators: {
      onBlur: schema,
    },
    defaultValues: {
      foo: "",
    },
    onSubmit() {},
  });

  useImperativeHandle(ref, () => form, [form]);

  return (
    <form onSubmit={handleFormElementSubmitEvent(form)}>
      <form.Field name="foo">
        {(field) => (
          <FormInputLayout fieldApi={field}>
            <Input />
          </FormInputLayout>
        )}
      </form.Field>
      <FormSubmit formApi={form}>Submit</FormSubmit>
    </form>
  );
}
