"use client";

import { type Dispatch, useEffect, useRef, useState } from "react";

import {
  getPaymentUrl,
  getStripeCustomerSessionClientSecret,
  getStripeClientSecret,
  isEzpayPayment,
  launchEzpayRedirect,
  resolveEzpayLaunchTarget,
} from "@/lib/payment/payment_launch";
import { behaviorAnalytics } from "@/lib/analytics";
import type {
  PendingPaymentReturnTo,
  PendingPaymentSubscriptionType,
} from "@/lib/payment/pending_payment_order";
import type {
  PaymentContextState,
} from "@/stores/payment/payment-context";
import type { PaymentEvent } from "@/stores/payment/payment-events";
import { AppEnvUtil } from "@/utils/app-env";
import { Logger } from "@/utils/logger";

const UNSUPPORTED_PAYMENT_PARAMS_MESSAGE =
  "Payment parameters did not include a supported URL or Stripe client secret.";

export interface ShouldShowEzpayConfirmationInput {
  currentOrderId: string | null;
  isProduction: boolean;
  payParams: Record<string, unknown> | null;
  paymentUrl: string | null;
}

export interface UsePaymentLaunchFlowInput {
  log: Logger;
  logScope: string;
  payment: PaymentContextState;
  paymentDispatch: Dispatch<PaymentEvent>;
  returnTo?: PendingPaymentReturnTo;
  characterSlug?: string;
  subscriptionType: PendingPaymentSubscriptionType;
  giftCategory?: string | null;
  giftPlanId?: string | null;
}

export interface PaymentLaunchFlow {
  ezpayPaymentUrl: string | null;
  handleEzpayCancel: () => void;
  handleEzpayConfirm: () => void;
  handleQrisClose: () => void;
  handleQrisResume: () => void;
  handleStripeClose: () => void;
  handleStripeConfirmed: () => void;
  hasHiddenQrisPayment: boolean;
  isConfirmingEzpay: boolean;
  qrisErrorMessage: string | null;
  qrisPayment: QrisPaymentDetails | null;
  qrisStatus: PaymentContextState["orderStatus"];
  resetLaunchState: () => void;
  shouldShowEzpayConfirmDialog: boolean;
  shouldShowQrisDialog: boolean;
  shouldShowStripeDialog: boolean;
  stripeClientSecret: string | null;
  stripeCustomerSessionClientSecret: string | null;
  savedPaymentMethodsEnabled: boolean;
}

export interface QrisPaymentDetails {
  amountCents: number;
  currency: string;
  orderId: string;
  qrData: string;
}

function paymentParamString(
  payParams: Record<string, unknown>,
  ...keys: string[]
): string | null {
  for (const key of keys) {
    const value = payParams[key];
    if (typeof value === "string" && value.trim()) return value.trim();
  }
  return null;
}

function paymentParamAmountCents(
  payParams: Record<string, unknown>,
): number | null {
  for (const key of [
    "firstChargeAmountCents",
    "first_charge_amount_cents",
    "amountCents",
    "amount_cents",
  ]) {
    const value = payParams[key];
    if (typeof value === "number" && Number.isFinite(value) && value > 0) {
      return value;
    }
  }
  return null;
}

function trackPaymentCheckoutOpened(
  payment: PaymentContextState,
  checkoutUrl: string,
): void {
  const plan = payment.plans.find(
    (item) => item.planId === payment.selectedPlanId,
  );
  if (!payment.currentOrderId || !plan) return;
  behaviorAnalytics.checkoutOpened({
    orderId: payment.currentOrderId,
    plan,
    payChannel: payment.payChannel,
    checkoutUrl,
  });
}

function trackPaymentCheckoutFailed(
  payment: PaymentContextState,
  reason: "missing_checkout_url" | "payment_redirect_failed",
): void {
  const plan = payment.plans.find(
    (item) => item.planId === payment.selectedPlanId,
  );
  if (!payment.currentOrderId || !plan) return;
  behaviorAnalytics.checkoutFailed({
    orderId: payment.currentOrderId,
    plan,
    payChannel: payment.payChannel,
    reason,
  });
}

export function shouldShowEzpayConfirmation({
  currentOrderId,
  isProduction,
  payParams,
  paymentUrl,
}: ShouldShowEzpayConfirmationInput): boolean {
  return Boolean(
    !isProduction &&
      payParams &&
      isEzpayPayment(payParams) &&
      paymentUrl &&
      currentOrderId,
  );
}

export function usePaymentLaunchFlow({
  log,
  logScope,
  payment,
  paymentDispatch,
  returnTo,
  characterSlug,
  subscriptionType,
  giftCategory,
  giftPlanId,
}: UsePaymentLaunchFlowInput): PaymentLaunchFlow {
  const launchedNonceRef = useRef(0);
  const [hiddenStripeClientSecret, setHiddenStripeClientSecret] = useState<
    string | null
  >(null);
  const [isConfirmingEzpay, setIsConfirmingEzpay] = useState(false);
  const [hiddenQrisOrderId, setHiddenQrisOrderId] = useState<string | null>(
    null,
  );
  const stripeClientSecret = payment.payParams
    ? getStripeClientSecret(payment.payParams)
    : null;
  const stripeCustomerSessionClientSecret = payment.payParams
    ? getStripeCustomerSessionClientSecret(payment.payParams)
    : null;
  const ezpayLaunchTarget =
    payment.payParams && isEzpayPayment(payment.payParams)
      ? resolveEzpayLaunchTarget(payment.payParams)
      : null;
  const ezpayPaymentUrl =
    ezpayLaunchTarget?.kind === "url"
      ? ezpayLaunchTarget.paymentUrl
      : null;
  const selectedPlan = payment.plans.find(
    (item) => item.planId === payment.selectedPlanId,
  );
  const qrisPayment: QrisPaymentDetails | null =
    payment.payParams &&
    payment.currentOrderId &&
    ezpayLaunchTarget?.kind === "qr"
      ? {
          amountCents:
            paymentParamAmountCents(payment.payParams) ??
            selectedPlan?.amountCents ??
            0,
          currency:
            paymentParamString(payment.payParams, "currency") ??
            selectedPlan?.currency ??
            "IDR",
          orderId: payment.currentOrderId,
          qrData: ezpayLaunchTarget.qrData,
        }
      : null;
  useEffect(() => {
    if (!payment.payParams || payment.launchNonce <= launchedNonceRef.current) {
      return;
    }

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

    const isEzpay = isEzpayPayment(payment.payParams);
    if (isEzpay) {
      const target = resolveEzpayLaunchTarget(payment.payParams);
      if (target.kind === "error") {
        trackPaymentCheckoutFailed(payment, "missing_checkout_url");
        paymentDispatch({
          type: "PaymentLaunchFailed",
          errorMessage: target.errorMessage,
        });
        return;
      }

      if (target.kind === "qr") {
        if (!payment.currentOrderId) {
          trackPaymentCheckoutFailed(payment, "missing_checkout_url");
          paymentDispatch({
            type: "PaymentLaunchFailed",
            errorMessage: "Missing order id before showing QRIS.",
          });
          return;
        }
        trackPaymentCheckoutOpened(payment, "qris_embedded");
        return;
      }

      const paymentUrl = target.paymentUrl;
      if (!AppEnvUtil.isProduction()) {
        log.debug(`[${logScope}] ezpay confirmation required`, {
          orderId: payment.currentOrderId,
          paymentUrl,
          subscriptionType,
        });
        return;
      }

      void launchEzpayRedirect({
        orderId: payment.currentOrderId,
        paymentUrl,
        subscriptionType,
        giftCategory,
        giftPlanId,
        ...(returnTo ? { returnTo } : {}),
        ...(characterSlug ? { characterSlug } : {}),
        onOpened: () => trackPaymentCheckoutOpened(payment, paymentUrl),
        onFailed: (errorMessage) => {
          trackPaymentCheckoutFailed(payment, "payment_redirect_failed");
          paymentDispatch({ type: "PaymentLaunchFailed", errorMessage });
        },
      });
      return;
    }

    const paymentUrl = getPaymentUrl(payment.payParams);
    if (paymentUrl) {
      try {
        window.location.href = paymentUrl;
        trackPaymentCheckoutOpened(payment, paymentUrl);
      } catch {
        trackPaymentCheckoutFailed(payment, "payment_redirect_failed");
        paymentDispatch({
          type: "PaymentLaunchFailed",
          errorMessage: "Could not open the payment page. Please try again.",
        });
      }
      return;
    }

    trackPaymentCheckoutFailed(payment, "missing_checkout_url");
    paymentDispatch({
      type: "PaymentLaunchFailed",
      errorMessage: UNSUPPORTED_PAYMENT_PARAMS_MESSAGE,
    });
  }, [
    log,
    logScope,
    characterSlug,
    payment.currentOrderId,
    payment,
    payment.launchNonce,
    payment.payChannel,
    payment.payParams,
    payment.plans,
    payment.selectedPlanId,
    paymentDispatch,
    returnTo,
    subscriptionType,
    giftCategory,
    giftPlanId,
  ]);

  const shouldShowStripeDialog =
    stripeClientSecret !== null &&
    stripeClientSecret !== hiddenStripeClientSecret &&
    !payment.isPaid;
  const shouldShowEzpayConfirmDialog = shouldShowEzpayConfirmation({
    currentOrderId: payment.currentOrderId,
    isProduction: AppEnvUtil.isProduction(),
    payParams: payment.payParams,
    paymentUrl: ezpayPaymentUrl,
  });
  const shouldShowQrisDialog = Boolean(
    qrisPayment &&
      qrisPayment.orderId !== hiddenQrisOrderId &&
      !payment.isPaid,
  );
  const hasHiddenQrisPayment = Boolean(
    qrisPayment &&
      qrisPayment.orderId === hiddenQrisOrderId &&
      payment.isPollingOrder &&
      !payment.isPaid,
  );

  function resetLaunchState(): void {
    setIsConfirmingEzpay(false);
    setHiddenStripeClientSecret(null);
    setHiddenQrisOrderId(null);
  }

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

  function handleStripeConfirmed(): void {
    if (stripeClientSecret) {
      setHiddenStripeClientSecret(stripeClientSecret);
    }
  }

  function handleEzpayConfirm(): void {
    if (!payment.currentOrderId || !ezpayPaymentUrl) return;
    setIsConfirmingEzpay(true);
    void launchEzpayRedirect({
      orderId: payment.currentOrderId,
      paymentUrl: ezpayPaymentUrl,
      subscriptionType,
      giftCategory,
      giftPlanId,
      ...(returnTo ? { returnTo } : {}),
      ...(characterSlug ? { characterSlug } : {}),
      onOpened: () => trackPaymentCheckoutOpened(payment, ezpayPaymentUrl),
      onFailed: (errorMessage) => {
        trackPaymentCheckoutFailed(payment, "payment_redirect_failed");
        setIsConfirmingEzpay(false);
        paymentDispatch({ type: "PaymentLaunchFailed", errorMessage });
      },
    });
  }

  function handleEzpayCancel(): void {
    log.debug(`[${logScope}] ezpay confirmation cancelled`, {
      orderId: payment.currentOrderId,
      subscriptionType,
    });
    setIsConfirmingEzpay(false);
    paymentDispatch({ type: "PaymentReset" });
  }

  function handleQrisClose(): void {
    log.debug(`[${logScope}] qris dialog closed`, {
      orderId: qrisPayment?.orderId ?? payment.currentOrderId,
      subscriptionType,
    });
    setHiddenQrisOrderId(qrisPayment?.orderId ?? payment.currentOrderId);
  }

  function handleQrisResume(): void {
    if (!hasHiddenQrisPayment) return;
    log.debug(`[${logScope}] qris dialog resumed`, {
      orderId: qrisPayment?.orderId ?? payment.currentOrderId,
      subscriptionType,
    });
    setHiddenQrisOrderId(null);
  }

  return {
    ezpayPaymentUrl,
    handleEzpayCancel,
    handleEzpayConfirm,
    handleQrisClose,
    handleQrisResume,
    handleStripeClose,
    handleStripeConfirmed,
    hasHiddenQrisPayment,
    isConfirmingEzpay,
    qrisErrorMessage: payment.errorMessage,
    qrisPayment,
    qrisStatus: payment.orderStatus,
    resetLaunchState,
    shouldShowEzpayConfirmDialog,
    shouldShowQrisDialog,
    shouldShowStripeDialog,
    stripeClientSecret,
    stripeCustomerSessionClientSecret,
    savedPaymentMethodsEnabled:
      stripeCustomerSessionClientSecret !== null,
  };
}
