"use client";
/**
 * 订阅 checkout 触发按钮
 *
 * 包装 `SubscriptionCtaButton` —— 通过 payment 状态机创建后端订单并拉起支付。
 */
import { useEffect, useRef, useState } from "react";

import { PendingPaymentOrderStorage } from "@/data/storage";
import {
  usePaymentDispatch,
  usePaymentState,
} from "@/stores/payment/payment-context";
import { AppEnvUtil, Logger, Result } from "@/utils";

import { StripePaymentDialog } from "./stripe-payment-dialog";
import { SubscriptionCtaButton } from "./subscription-cta-button";
import styles from "./subscription-cta-button.module.css";

const EZPAY_DEVELOPMENT_REDIRECT_DELAY_MS = 10000;
const log = new Logger("SubscriptionCheckoutButton");

export interface SubscriptionCheckoutButtonProps {
  /** 是否可用（未选套餐 / 未勾选协议 → false） */
  disabled?: boolean;
  subscriptionType: "vip" | "voice";
}

export function SubscriptionCheckoutButton({
  disabled = false,
  subscriptionType,
}: SubscriptionCheckoutButtonProps) {
  const payment = usePaymentState();
  const paymentDispatch = usePaymentDispatch();
  const launchedNonceRef = useRef(0);
  const ezpayRedirectTimeoutRef = useRef<number | null>(null);
  const [hiddenStripeClientSecret, setHiddenStripeClientSecret] = useState<
    string | null
  >(null);

  useEffect(() => {
    return () => {
      if (ezpayRedirectTimeoutRef.current !== null) {
        window.clearTimeout(ezpayRedirectTimeoutRef.current);
      }
    };
  }, []);

  useEffect(() => {
    if (!payment.payParams || payment.launchNonce <= launchedNonceRef.current) {
      return;
    }

    launchedNonceRef.current = payment.launchNonce;
    const clientSecret = getStripeClientSecret(payment.payParams);
    if (clientSecret) {
      return;
    }

    const paymentUrl = getPaymentUrl(payment.payParams);
    if (paymentUrl) {
      const isEzpay = isEzpayPayment(payment.payParams);

      if (!AppEnvUtil.isProduction() && isEzpay) {
        if (ezpayRedirectTimeoutRef.current !== null) {
          window.clearTimeout(ezpayRedirectTimeoutRef.current);
        }

        void redirectToEzpay({
          orderId: payment.currentOrderId,
          paymentUrl,
          subscriptionType,
          delayMs: EZPAY_DEVELOPMENT_REDIRECT_DELAY_MS,
          setTimeoutId: (timeoutId) => {
            ezpayRedirectTimeoutRef.current = timeoutId;
          },
        });
        return;
      }

      if (isEzpay) {
        void redirectToEzpay({
          orderId: payment.currentOrderId,
          paymentUrl,
          subscriptionType,
        });
        return;
      }

      window.location.href = paymentUrl;
      return;
    }

    paymentDispatch({
      type: "PaymentLaunchFailed",
      errorMessage:
        "Payment parameters did not include a supported URL or Stripe client secret.",
    });
  }, [
    payment.currentOrderId,
    payment.launchNonce,
    payment.payParams,
    paymentDispatch,
    subscriptionType,
  ]);

  const isLoading =
    payment.isCreatingOrder ||
    payment.isPollingOrder ||
    payment.isCheckingVipStatus;
  const label = payment.isPollingOrder
      ? "Processing payment..."
      : payment.isCreatingOrder
        ? "Creating order..."
        : payment.agreed
          ? "Pay and Activiate"
          : "Confirm the agreement and Activate";

  const handleClick = () => {
    if (disabled || isLoading) return;
    if (ezpayRedirectTimeoutRef.current !== null) {
      window.clearTimeout(ezpayRedirectTimeoutRef.current);
      ezpayRedirectTimeoutRef.current = null;
    }
    setHiddenStripeClientSecret(null);
    paymentDispatch({ type: "PaymentCreateOrderSubmitted" });
  };

  const handleStripeClose = () => {
    if (stripeClientSecret) {
      setHiddenStripeClientSecret(stripeClientSecret);
    }
    if (payment.orderStatus !== "paid") {
      paymentDispatch({ type: "PaymentReset" });
    }
  };

  const handleStripeConfirmed = () => {
    if (stripeClientSecret) {
      setHiddenStripeClientSecret(stripeClientSecret);
    }
  };

  const stripeClientSecret = payment.payParams
    ? getStripeClientSecret(payment.payParams)
    : null;
  const shouldShowStripeDialog =
    stripeClientSecret !== null &&
    stripeClientSecret !== hiddenStripeClientSecret &&
    !payment.isPaid;
  const pendingEzpayRedirectOrderId =
    !AppEnvUtil.isProduction() &&
    payment.payParams &&
    isEzpayPayment(payment.payParams) &&
    getPaymentUrl(payment.payParams) &&
    payment.currentOrderId
      ? payment.currentOrderId
      : null;

  return (
    <>
      <SubscriptionCtaButton
        type="button"
        disabled={disabled}
        isLoading={isLoading}
        onClick={handleClick}
        className={styles.button}
      >
        {label}
      </SubscriptionCtaButton>
      {payment.errorMessage ? (
        <p
          role="alert"
          style={{
            color: "#c0392b",
            fontSize: "0.875rem",
            marginTop: "0.5rem",
            textAlign: "center",
          }}
        >
          {payment.errorMessage}
        </p>
      ) : null}
      {pendingEzpayRedirectOrderId ? (
        <div className={styles.pendingRedirect} role="status">
          <span className={styles.pendingRedirectLabel}>
            Ezpay order created. Redirecting in 5 seconds.
          </span>
          <span className={styles.pendingRedirectOrder}>
            Order No. {pendingEzpayRedirectOrderId}
          </span>
        </div>
      ) : null}
      {shouldShowStripeDialog ? (
        <StripePaymentDialog
          clientSecret={stripeClientSecret}
          onClose={handleStripeClose}
          onConfirmed={handleStripeConfirmed}
        />
      ) : null}
    </>
  );
}

function getPaymentUrl(payParams: Record<string, unknown>): string | null {
  const keys = [
    "cashierUrl",
    "cashier_url",
    "checkoutUrl",
    "checkout_url",
    "paymentUrl",
    "payment_url",
    "approvalUrl",
    "approval_url",
    "redirectUrl",
    "redirect_url",
    "url",
  ];

  for (const key of keys) {
    const value = payParams[key];
    if (typeof value === "string" && value.length > 0) return value;
  }

  return null;
}

function isEzpayPayment(payParams: Record<string, unknown>): boolean {
  const provider = payParams.provider;
  return typeof provider === "string" && provider.toLowerCase() === "ezpay";
}

interface RedirectToEzpayInput {
  orderId: string | null;
  paymentUrl: string;
  subscriptionType: "vip" | "voice";
  delayMs?: number;
  setTimeoutId?: (timeoutId: number) => void;
}

async function redirectToEzpay({
  orderId,
  paymentUrl,
  subscriptionType,
  delayMs = 0,
  setTimeoutId,
}: RedirectToEzpayInput): Promise<void> {
  log.debug("[subscription-checkout] redirectToEzpay START", {
    hasOrderId: Boolean(orderId),
    orderId,
    subscriptionType,
    delayMs,
    paymentUrl,
  });

  if (orderId) {
    const saveResult = await PendingPaymentOrderStorage.setPendingOrder({
      orderId,
      payChannel: "ezpay",
      subscriptionType,
      createdAt: Date.now(),
    });
    if (Result.isOk(saveResult)) {
      log.debug("[subscription-checkout] pending ezpay order saved", {
        orderId,
        subscriptionType,
      });
    } else {
      log.error("[subscription-checkout] pending ezpay order save failed", {
        orderId,
        subscriptionType,
        error: saveResult.error,
      });
    }
  } else {
    log.warn("[subscription-checkout] skip pending ezpay order save: missing orderId", {
      subscriptionType,
      paymentUrl,
    });
  }

  if (delayMs > 0) {
    const timeoutId = window.setTimeout(() => {
      log.debug("[subscription-checkout] redirectToEzpay DELAY elapsed", {
        orderId,
        subscriptionType,
        paymentUrl,
      });
      window.location.href = paymentUrl;
    }, delayMs);
    setTimeoutId?.(timeoutId);
    log.debug("[subscription-checkout] redirectToEzpay DELAY scheduled", {
      orderId,
      subscriptionType,
      delayMs,
      timeoutId,
    });
    return;
  }

  log.debug("[subscription-checkout] redirectToEzpay NOW", {
    orderId,
    subscriptionType,
    paymentUrl,
  });
  window.location.href = paymentUrl;
}

function getStripeClientSecret(
  payParams: Record<string, unknown>,
): string | null {
  const provider = payParams.provider;
  const clientSecret = payParams.clientSecret ?? payParams.client_secret;
  const isStripeProvider =
    typeof provider !== "string" || provider.toLowerCase() === "stripe";

  if (
    isStripeProvider &&
    typeof clientSecret === "string" &&
    clientSecret.length > 0
  ) {
    return clientSecret;
  }

  return null;
}
