import clsx from "clsx";
import { type ReactNode, useState, useEffect } from "react";
import type { Navigation } from "react-router";
import { IBlockProps, createBlockComponent } from "#components/meta";
import { Details } from "#components/details";
import { ErrorView } from "#components/errors";
import { FormSection } from "./sections/section";
import { ButtonSubmit } from "./submit_button";
import { ISubmitEvent } from "./types";

import * as styles from "./client.module.scss";

export interface IFormClientProps
  extends Omit<IBlockProps<"form">, "onSubmit" | "children"> {
  onSubmit: (event: ISubmitEvent) => Promise<void>;
  statusSection?: null;
  submitButton?: (state: Navigation["state"]) => ReactNode;
  children?: ReactNode | ((state: Navigation["state"]) => ReactNode);
}

/**
 * A form which only works client-side.
 *
 * Because I have no idea how to make an "actionless"
 * `react-router` form.
 */
export const FormClient = createBlockComponent(styles, Component);

export function Component({
  className,
  children,
  onSubmit,
  submitButton,
  statusSection,
  ...props
}: IFormClientProps) {
  const [state, changeStatus] = useState<Navigation["state"]>("loading");
  const [error, changeError] = useState<Error>();

  useEffect(() => changeStatus("idle"), []);

  async function handleSubmit(event: ISubmitEvent) {
    event.preventDefault();

    if (state !== "idle") {
      return;
    }

    try {
      changeStatus("submitting");
      await onSubmit(event);
      changeError(undefined);
    } catch (error) {
      changeError(error as Error);
    } finally {
      changeStatus("idle");
    }
  }

  return (
    <form
      className={clsx("form", className)}
      {...props}
      onSubmit={handleSubmit}
    >
      {typeof children !== "function" ? children : children(state)}

      {statusSection === null ? undefined : (
        <FormSection>
          {state === "loading" ? (
            "Loading..."
          ) : state === "submitting" ? (
            "Submitting..."
          ) : error ? (
            <ul>
              <li>
                <Details summary={"Error details"}>
                  <ErrorView error={error} />
                </Details>
              </li>
            </ul>
          ) : (
            "Ready for submit"
          )}
        </FormSection>
      )}

      {submitButton && (
        <FormSection>
          <ButtonSubmit disabled={state !== "idle"}>
            {submitButton(state)}
          </ButtonSubmit>
        </FormSection>
      )}
    </form>
  );
}
