import { Form } from "@ariakit/react";
import {
  getSubmitFailureMessage,
  Letterhead,
  LetterheadHeading,
  LetterheadParagraph,
  LetterheadSubmitButton,
  LetterheadSubmitError,
  useForm,
  type RedeemedPledge,
} from "@indietabletop/appkit";
import { useState, type ReactNode } from "react";
import { useClient } from "../AppConfig/AppConfig.tsx";
import { LetterheadInfoCard } from "./LetterheadInfoCard.tsx";
import * as css from "./style.css.ts";

type Pledge = Pick<RedeemedPledge, "id" | "email" | "contactSubscribed">;

function SubscribeView(
  props: ViewContent & {
    onSuccess: () => void;
    pledge: Pledge;
  },
) {
  const { pledge, title, description, onSuccess } = props;

  const client = useClient();
  const { form, submitName } = useForm({
    defaultValues: {},
    onSuccess,
    async onSubmit() {
      const result = await client.subscribeToNewsletterByPledgeId(
        "changelog",
        pledge.id,
      );

      return result.mapFailure(getSubmitFailureMessage);
    },
  });

  return (
    <Letterhead>
      <LetterheadHeading className={css.card.heading}>
        {title}
      </LetterheadHeading>

      {description}

      <Form store={form} className={css.card.form}>
        <LetterheadSubmitError name={submitName} />

        <LetterheadSubmitButton>Subscribe</LetterheadSubmitButton>

        <LetterheadParagraph size="small">
          Using {pledge.email} from your pledge.
        </LetterheadParagraph>
      </Form>
    </Letterhead>
  );
}

type SubscribeStep =
  | "PREVIOUSLY_SUBSCRIBED"
  | "SUBSCRIBE"
  | "SUBSCRIBE_SUCCESS";

export type ViewContent = {
  title: ReactNode;
  description: ReactNode;
};

/**
 * Allows users to sign up to the newsletter using the email associated with
 * their pledge ID.
 *
 * Emails are not verified using a one-time code, as the user has just
 * implicitly verified their address by navigating to the page with the unique
 * pledge ID.
 */
export function SubscribeByPledgeCard(props: {
  /**
   * The pledge data that will be used to determine whether the user should
   * be prompted for signup.
   */
  pledge: Pledge;

  /**
   * Content for each of the subscribe steps. You probably want to customize it
   * for each step, so it is left to be defined at point of usage.
   *
   * If the `description` is a string, it will be wrapped in
   * `<LetterheadParagraph>`, otherwise it will be left as is.
   */
  content: Record<SubscribeStep, ViewContent>;
}) {
  const { pledge } = props;

  const [step, setStep] = useState<SubscribeStep>(
    pledge.contactSubscribed ? "PREVIOUSLY_SUBSCRIBED" : "SUBSCRIBE",
  );

  const content = props.content[step];

  switch (step) {
    case "SUBSCRIBE": {
      return (
        <SubscribeView
          {...props}
          {...content}
          onSuccess={() => void setStep("SUBSCRIBE_SUCCESS")}
        />
      );
    }

    case "PREVIOUSLY_SUBSCRIBED":
    case "SUBSCRIBE_SUCCESS": {
      return <LetterheadInfoCard {...content} />;
    }
  }
}

export {
  /**
   * @deprecated Use {@link SubscribeByPledgeCard}
   */
  SubscribeByPledgeCard as SubscribeCard,
};
