import type { PaymentMethod } from "@customer-portal/domain/payments";

const isCreditCard = (type: PaymentMethod["type"]) =>
  type === "CreditCard" || type === "RemoteCreditCard";

const isBankAccount = (type: PaymentMethod["type"]) =>
  type === "BankAccount" || type === "RemoteBankAccount";

const getTrimmedLastFour = (method: PaymentMethod): string | null => {
  const lastFour = typeof method.cardLastFour === "string" ? method.cardLastFour.trim() : "";
  return lastFour.length > 0 ? lastFour.slice(-4) : null;
};

function getDescriptor(method: PaymentMethod): string {
  return (
    method.cardType?.trim() ||
    method.bankName?.trim() ||
    method.description?.trim() ||
    method.gatewayName?.trim() ||
    "Saved payment method"
  );
}

function buildHeadline(descriptor: string, trimmedLastFour: string | null, type?: string): string {
  if (trimmedLastFour && type?.toLowerCase().includes("card")) {
    return `${descriptor} · •••• ${trimmedLastFour}`;
  }
  return descriptor;
}

function collectDetails(
  method: PaymentMethod,
  headline: string,
  trimmedLastFour: string | null
): Set<string> {
  const details = new Set<string>();

  if (method.bankName && !headline.toLowerCase().includes(method.bankName.trim().toLowerCase())) {
    details.add(method.bankName.trim());
  }

  const expiry = normalizeExpiryLabel(method.expiryDate);
  if (expiry) details.add(`Exp ${expiry}`);

  if (!trimmedLastFour && method.cardLastFour && method.cardLastFour.trim().length > 0) {
    details.add(`Ends ${method.cardLastFour.trim().slice(-4)}`);
  }

  if (method.type?.toLowerCase().includes("bank") && method.description?.trim()) {
    details.add(method.description.trim());
  }

  return details;
}

export function buildPaymentMethodDisplay(method: PaymentMethod): {
  title: string;
  subtitle?: string | undefined;
} {
  const descriptor = getDescriptor(method);
  const trimmedLastFour = getTrimmedLastFour(method);
  const headline = buildHeadline(descriptor, trimmedLastFour, method.type);
  const details = collectDetails(method, headline, trimmedLastFour);
  const subtitle = details.size > 0 ? [...details].join(" · ") : undefined;
  return { title: headline, subtitle };
}

const EXPIRY_REGEX_YYYY_MM = /^\d{4}-\d{2}$/;
const EXPIRY_REGEX_MM_YYYY = /^\d{2}\/\d{4}$/;
const EXPIRY_REGEX_MM_YY = /^\d{2}\/\d{2}$/;
const NON_DIGIT_REGEX = /\D/g;

export function normalizeExpiryLabel(expiry?: string | null): string | null {
  if (!expiry) return null;
  const value = expiry.trim();
  if (!value) return null;

  if (EXPIRY_REGEX_YYYY_MM.test(value)) {
    const [year, month] = value.split("-");
    if (year && month) {
      return `${month}/${year.slice(-2)}`;
    }
  }

  if (EXPIRY_REGEX_MM_YYYY.test(value)) {
    const [month, year] = value.split("/");
    if (month && year) {
      return `${month}/${year.slice(-2)}`;
    }
  }

  if (EXPIRY_REGEX_MM_YY.test(value)) {
    return value;
  }

  const digits = value.replace(NON_DIGIT_REGEX, "");

  if (digits.length === 6) {
    const year = digits.slice(2, 4);
    const month = digits.slice(4, 6);
    return `${month}/${year}`;
  }

  if (digits.length === 4) {
    const month = digits.slice(0, 2);
    const year = digits.slice(2, 4);
    return `${month}/${year}`;
  }

  return value;
}

export function getPaymentMethodCardDisplay(method: PaymentMethod): string {
  const trimmedLastFour = getTrimmedLastFour(method);
  if (trimmedLastFour) {
    return `***** ${trimmedLastFour}`;
  }

  if (isCreditCard(method.type)) {
    return method.cardType ? `${method.cardType.toUpperCase()} Card` : "Credit Card";
  }

  if (isBankAccount(method.type)) {
    return method.bankName || "Bank Account";
  }

  return method.description || "Payment Method";
}

export function getPaymentMethodBrandLabel(method: PaymentMethod): string | null {
  if (isCreditCard(method.type) && method.cardType) {
    return method.cardType.toUpperCase();
  }

  if (isBankAccount(method.type) && method.bankName) {
    return method.bankName;
  }

  return null;
}
