"use client";

import { Logger } from "@/utils/logger";
import { Result } from "@/utils/result";

import {
  savePendingEzpayOrder,
  type PendingPaymentReturnTo,
  type PendingPaymentSubscriptionType,
} from "./pending_payment_order";

const log = new Logger("LibPaymentPaymentLaunch");

export type EzpayLaunchTarget =
  | { kind: "url"; paymentUrl: string }
  | { kind: "qr"; qrData: string }
  | { kind: "error"; errorMessage: string };

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

function getHttpPaymentUrl(value: string | null): string | null {
  if (!value) return null;
  try {
    const parsed = new URL(value);
    return parsed.protocol === "https:" || parsed.protocol === "http:"
      ? value
      : null;
  } catch {
    return null;
  }
}

export 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;
}

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

export function resolveEzpayLaunchTarget(
  payParams: Record<string, unknown>,
): EzpayLaunchTarget {
  const rawChannelType = getNonEmptyString(
    payParams,
    "channelType",
    "channel_type",
  );
  const channelType = rawChannelType?.toUpperCase() ?? null;
  const payData = getNonEmptyString(payParams, "payData", "pay_data");

  if (channelType === "QR") {
    return payData
      ? { kind: "qr", qrData: payData }
      : {
          kind: "error",
          errorMessage: "QRIS payment data is missing. Please try again.",
        };
  }

  if (channelType === "VA") {
    return {
      kind: "error",
      errorMessage: "Virtual account payments are not supported in this app.",
    };
  }

  if (channelType === "URL") {
    const paymentUrl =
      getHttpPaymentUrl(payData) ?? getHttpPaymentUrl(getPaymentUrl(payParams));
    return paymentUrl
      ? { kind: "url", paymentUrl }
      : {
          kind: "error",
          errorMessage: "Ezpay payment URL is missing or invalid. Please try again.",
        };
  }

  if (channelType) {
    return {
      kind: "error",
      errorMessage: `Unsupported Ezpay payment channel: ${channelType}.`,
    };
  }

  const legacyPaymentUrl = getHttpPaymentUrl(getPaymentUrl(payParams));
  return legacyPaymentUrl
    ? { kind: "url", paymentUrl: legacyPaymentUrl }
    : {
        kind: "error",
        errorMessage:
          "Ezpay payment parameters did not include a supported URL or QRIS code.",
      };
}

export 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;
}

export function getStripeCustomerSessionClientSecret(
  payParams: Record<string, unknown>,
): string | null {
  const provider = payParams.provider;
  const isStripeProvider =
    typeof provider !== "string" || provider.toLowerCase() === "stripe";
  const enabled = payParams.savedPaymentMethodsEnabled === true;
  const clientSecret = payParams.customerSessionClientSecret;

  if (
    isStripeProvider &&
    enabled &&
    typeof clientSecret === "string" &&
    /^cuss_[^\s]+_secret_[^\s]+$/i.test(clientSecret)
  ) {
    return clientSecret;
  }

  return null;
}

export interface LaunchEzpayRedirectInput {
  orderId: string | null;
  paymentUrl: string;
  subscriptionType: PendingPaymentSubscriptionType;
  giftCategory?: string | null;
  giftPlanId?: string | null;
  returnTo?: PendingPaymentReturnTo;
  characterSlug?: string;
  onOpened?: () => void;
  onFailed: (errorMessage: string) => void;
}

export async function launchEzpayRedirect({
  orderId,
  paymentUrl,
  subscriptionType,
  giftCategory,
  giftPlanId,
  returnTo,
  characterSlug,
  onOpened,
  onFailed,
}: LaunchEzpayRedirectInput): Promise<void> {
  log.debug("[payment-launch] launchEzpayRedirect START", {
    hasOrderId: Boolean(orderId),
    orderId,
    subscriptionType,
    paymentUrl,
  });

  if (!orderId) {
    const errorMessage = "Missing order id before opening Ezpay.";
    log.error("[payment-launch] pending ezpay order save skipped", {
      subscriptionType,
      paymentUrl,
      errorMessage,
    });
    onFailed(errorMessage);
    return;
  }

  const saveResult = await savePendingEzpayOrder({
    orderId,
    subscriptionType,
    giftCategory,
    giftPlanId,
    ...(returnTo ? { returnTo } : {}),
    ...(characterSlug ? { characterSlug } : {}),
  });
  if (Result.isErr(saveResult)) {
    const errorMessage =
      "Could not save payment order before opening Ezpay. Please try again.";
    log.error("[payment-launch] pending ezpay order save failed", {
      orderId,
      subscriptionType,
      error: saveResult.error,
    });
    onFailed(errorMessage);
    return;
  }

  log.debug("[payment-launch] pending ezpay order saved", {
    orderId,
    subscriptionType,
  });

  log.debug("[payment-launch] launchEzpayRedirect NOW", {
    orderId,
    subscriptionType,
    paymentUrl,
  });
  try {
    window.location.href = paymentUrl;
    onOpened?.();
  } catch {
    onFailed("Could not open Ezpay. Please try again.");
  }
}
