import { useBillingConfig } from "@/components/billing/billing-context";
import { useUserBillingProfile } from "@/components/billing/hooks";
import { FormServerErrors } from "@/components/form-common/form-server-errors";
import { FormSubmit } from "@/components/form-common/form-submit";
import { RegionSelect } from "@/components/form-fields/region-select";
import {
  fieldItemProps,
  fieldLabelProps,
  fieldMessageProps,
  formInputProps,
  formSelectProps,
} from "@/components/tanstack-form-utils";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useLocaleFunction } from "@/hooks/use-localed";
import { toast } from "@/hooks/use-toast";
import {
  type BillingDetails,
  updateUserBillingDetails,
} from "@/lib/api/billing";
import { getErrorMessage, Standard400Error } from "@/lib/errors";
import { handleFormElementSubmitEvent, handleSubmitErrors } from "@/lib/form";
import { cn } from "@/lib/utils";
import { type FormApi, type ReactFormApi, useForm } from "@tanstack/react-form";
import { useEffect, useId } from "react";
import { z } from "zod";

export const billingDetailsSchema = z.object({
  line1: z.string(),
  line2: z.string(),
  city: z.string(),
  state: z.string(),
  postal_code: z.string(),
  country: z.string(),
});

export const defaultBillingDetails: BillingDetails = {
  line1: "",
  line2: "",
  city: "",
  state: "",
  postal_code: "",
  country: "",
};

export function UpdateBillingDetailsForm({
  className,
}: {
  className?: string;
}) {
  const { data, refetch } = useUserBillingProfile();

  const form = useForm({
    validators: {
      onBlur: billingDetailsSchema,
      onSubmit: billingDetailsSchema,
    },
    defaultValues: data?.billing_details ?? defaultBillingDetails,
    onSubmit: async ({ value, formApi }) => {
      await handleSubmitErrors(formApi, async () => {
        try {
          await updateUserBillingDetails(value);
          await refetch();
          toast({
            title: t("payment.toasts.succeed-to-update-billing-details"),
          });
        } catch (e) {
          if (!Standard400Error.isStandard400Error(e)) {
            toast({
              title: t("payment.alerts.failed-to-update-billing-details"),
              description: getErrorMessage(e),
            });
          }
          return Promise.reject(e);
        }
      });
    },
  });

  const t = useLocaleFunction();

  return (
    <form
      className={cn("space-y-4", className)}
      onSubmit={handleFormElementSubmitEvent(form)}
    >
      <BillingDetailsFields formApi={form} />
      <FormServerErrors
        formApi={form}
        title={t("payment.alerts.failed-to-update-billing-details")}
      />
      <FormSubmit formApi={form}>
        {t("payment.billing-details.update")}
      </FormSubmit>
    </form>
  );
}

export function ConfirmBillingDetailsForm({
  className,
  defaultValues,
  onSubmit,
}: {
  className?: string;
  defaultValues?: BillingDetails | null;
  onSubmit: (address: BillingDetails, changed: boolean) => Promise<void>;
}) {
  const form = useForm({
    validators: {
      onBlur: billingDetailsSchema,
      onSubmit: billingDetailsSchema,
    },
    defaultValues: defaultValues ?? defaultBillingDetails,
    async onSubmit({ value, formApi }) {
      await handleSubmitErrors(formApi, async () => {
        await onSubmit(value, formApi.state.isDirty);
      });
    },
  });

  const t = useLocaleFunction();

  return (
    <form
      className={cn("space-y-4", className)}
      onSubmit={handleFormElementSubmitEvent(form)}
    >
      <BillingDetailsFields formApi={form} />
      <FormSubmit className="flex w-full" formApi={form}>
        {t("payment.billing-details.complete.confirm")}
      </FormSubmit>
    </form>
  );
}

export function BillingDetailsFields({
  disabled,
  formApi: propFormApi,
}: {
  disabled?: boolean;
  formApi: FormApi<any, any, any, any, any, any, any, any, any, any, any, any> &
    ReactFormApi<any, any, any, any, any, any, any, any, any, any, any, any>;
}) {
  // MARK: typing issue
  const formApi = propFormApi as never as FormApi<
    BillingDetails,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  > &
    ReactFormApi<
      BillingDetails,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any
    > & {};

  const { allowed_countries } = useBillingConfig();
  const id = useId();
  const t = useLocaleFunction();

  useEffect(() => {
    return formApi.store.subscribe((state) => {
      if (state.prevVal.values.country !== state.currentVal.values.country) {
        if (state.currentVal.values.country === "US") {
          setTimeout(() => {
            formApi.setFieldValue("state", "CA");
          }, 0);
        }
      }
    });
  }, [formApi]);

  return (
    <>
      <formApi.Field name="country">
        {(field) => (
          <div className="space-y-2">
            <Label {...fieldLabelProps(field, id)}>
              {t("payment.billing-details.form.country")}
            </Label>
            <RegionSelect
              {...fieldItemProps(field, id)}
              {...formSelectProps(field, disabled)}
              allowedValues={allowed_countries}
              localeOverrides={{
                US: {
                  en: "United States (California)",
                  ja: "アメリカ合衆国（カリフォルニア州）",
                  zh: "美国（加利福尼亚州）",
                  ko: "United States (California)",
                },
              }}
            />
            <p {...fieldMessageProps(field, id)} />
          </div>
        )}
      </formApi.Field>
      <formApi.Field name="line1">
        {(field) => (
          <div className="space-y-2">
            <Label {...fieldLabelProps(field, id)}>
              {t("payment.billing-details.form.line1")}
            </Label>
            <Input
              {...fieldItemProps(field, id)}
              {...formInputProps(field, disabled)}
            />
            <p {...fieldMessageProps(field, id)} />
          </div>
        )}
      </formApi.Field>
      <formApi.Field name="line2">
        {(field) => (
          <div className="space-y-2">
            <Label {...fieldLabelProps(field, id)}>
              {t("payment.billing-details.form.line2")}
            </Label>
            <Input
              {...fieldItemProps(field, id)}
              {...formInputProps(field, disabled)}
            />
            <p {...fieldMessageProps(field, id)} />
          </div>
        )}
      </formApi.Field>
      <formApi.Field name="city">
        {(field) => (
          <div className="space-y-2">
            <Label {...fieldLabelProps(field, id)}>
              {t("payment.billing-details.form.city")}
            </Label>
            <Input
              {...fieldItemProps(field, id)}
              {...formInputProps(field, disabled)}
            />
            <p {...fieldMessageProps(field, id)} />
          </div>
        )}
      </formApi.Field>
      <div className="flex items-start gap-4 w-full">
        <formApi.Subscribe selector={(state) => state.values.country}>
          {(country) => (
            <formApi.Field name="state">
              {(field) => (
                <div className="flex-1 space-y-2">
                  <Label {...fieldLabelProps(field, id)}>
                    {t("payment.billing-details.form.state")}
                  </Label>
                  <Input
                    {...fieldItemProps(
                      field,
                      id,
                      "read-only:text-muted-foreground"
                    )}
                    {...formInputProps(field, disabled)}
                    readOnly={country === "US"}
                  />
                  <p {...fieldMessageProps(field, id)} />
                </div>
              )}
            </formApi.Field>
          )}
        </formApi.Subscribe>
        <formApi.Field name="postal_code">
          {(field) => (
            <div className="flex-1 space-y-2">
              <Label {...fieldLabelProps(field, id)}>
                {t("payment.billing-details.form.postal-code")}
              </Label>
              <Input
                {...fieldItemProps(field, id)}
                {...formInputProps(field, disabled)}
              />
              <p {...fieldMessageProps(field, id)} />
            </div>
          )}
        </formApi.Field>
      </div>
    </>
  );
}
