"use client";
/**
 * Stripe Payment Element 弹窗
 *
 * 后端当前返回 PaymentIntent clientSecret，因此这里直接用它完成前端确认。
 */
import { useState, type FormEvent } from "react";
import {
  Elements,
  PaymentElement,
  useElements,
  useStripe,
} from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";

import { ExceptionHandler } from "@/core/errors";
import { ROUTES } from "@/router/routes";
import { Logger } from "@/utils/logger";

import { stripePaymentDialogStyles as styles } from "./stripe-payment-dialog.styles";

const log = new Logger("SubscriptionStripePaymentDialog");
const stripePublishableKey = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;
const stripePromise = stripePublishableKey
  ? loadStripe(stripePublishableKey)
  : null;

export interface StripePaymentDialogProps {
  clientSecret: string;
  returnPath?: string;
  onClose: () => void;
  onConfirmed?: () => void;
}

export function StripePaymentDialog({
  clientSecret,
  returnPath = ROUTES.subscription + "/success",
  onClose,
  onConfirmed,
}: StripePaymentDialogProps) {
  if (!stripePromise) {
    return (
      <div className={styles.overlay} role="alertdialog" aria-modal="true">
        <div className={styles.dialog}>
          <div className={styles.header}>
            <h2 className={styles.title}>Payment unavailable</h2>
            <p className={styles.content}>
              Stripe publishable key is not configured for this build.
            </p>
          </div>
          <div className={styles.actions}>
            <button
              type="button"
              className={`${styles.button} ${styles.primary}`}
              onClick={onClose}
            >
              OK
            </button>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div
      className={styles.overlay}
      role="dialog"
      aria-modal="true"
      aria-labelledby="stripe-payment-title"
    >
      <div className={styles.dialog}>
        <div className={styles.header}>
          <h2 id="stripe-payment-title" className={styles.title}>
            Complete payment
          </h2>
          <p className={styles.content}>
            Enter your payment details securely through Stripe.
          </p>
        </div>
        <Elements
          key={clientSecret}
          stripe={stripePromise}
          options={{
            clientSecret,
            appearance: {
              theme: "stripe",
              variables: {
                borderRadius: "14px",
                colorPrimary: "#ff52a2",
                colorText: "#171717",
              },
            },
          }}
        >
          <StripePaymentForm
            returnPath={returnPath}
            onClose={onClose}
            onConfirmed={onConfirmed}
          />
        </Elements>
      </div>
    </div>
  );
}

function StripePaymentForm({
  returnPath,
  onClose,
  onConfirmed,
}: Pick<
  StripePaymentDialogProps,
  "returnPath" | "onClose" | "onConfirmed"
>) {
  const stripe = useStripe();
  const elements = useElements();
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleLoadError = (event: Parameters<
    NonNullable<React.ComponentProps<typeof PaymentElement>["onLoadError"]>
  >[0]) => {
    log.error("[stripe-payment-dialog] PaymentElement load failed", {
      type: event.error.type,
      code: event.error.code,
      message: event.error.message,
      declineCode: event.error.decline_code,
    });
    setErrorMessage(
      ExceptionHandler.message(
        event.error,
        "Payment methods could not be loaded. Please try again later.",
      ),
    );
  };

  const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (!stripe || !elements || isSubmitting) return;

    setIsSubmitting(true);
    setErrorMessage(null);

    const { error: submitError } = await elements.submit();
    if (submitError) {
      setErrorMessage(
        ExceptionHandler.message(submitError, "Please check your payment info."),
      );
      setIsSubmitting(false);
      return;
    }

    const returnUrl = new URL(
      returnPath ?? ROUTES.subscription + "/success",
      window.location.origin,
    );
    const { error } = await stripe.confirmPayment({
      elements,
      confirmParams: {
        return_url: returnUrl.toString(),
      },
      redirect: "if_required",
    });

    if (error) {
      setErrorMessage(
        ExceptionHandler.message(error, "Payment confirmation failed."),
      );
      setIsSubmitting(false);
      return;
    }

    onConfirmed?.();
  };

  return (
    <form className={styles.form} onSubmit={handleSubmit}>
      <PaymentElement onLoadError={handleLoadError} />
      {errorMessage ? (
        <p
          role="alert"
          className={styles.error}
        >
          {errorMessage}
        </p>
      ) : null}
      <div className={styles.actions}>
        <button
          type="button"
          className={`${styles.button} ${styles.secondary}`}
          onClick={onClose}
          disabled={isSubmitting}
        >
          Cancel
        </button>
        <button
          type="submit"
          className={`${styles.button} ${styles.primary}`}
          disabled={!stripe || !elements || isSubmitting}
        >
          {isSubmitting ? "Processing..." : "Pay now"}
        </button>
      </div>
    </form>
  );
}
