import { z } from "zod";

export enum PaymentMethod {
  Card = "card",
  // INFO: for other future payment methods
}

function isValidLuhn(cardNumber: string): boolean {
  const digits = cardNumber.replace(/\D/g, "");
  let sum = 0;
  let isEven = false;

  for (let i = digits.length - 1; i >= 0; i--) {
    let digit = parseInt(digits[i], 10);

    if (isEven) {
      digit *= 2;
      if (digit > 9) {
        digit -= 9;
      }
    }

    sum += digit;
    isEven = !isEven;
  }

  return sum % 10 === 0;
}

function isValidExpiry(expiryDate: string): boolean {
  const match = expiryDate.match(/^(0[1-9]|1[0-2])\/(\d{2})$/);
  if (!match) return false;

  const month = parseInt(match[1], 10);
  const year = parseInt(match[2], 10);

  const currentDate = new Date();
  const currentYear = currentDate.getFullYear() % 100; // Get last 2 digits of year
  const maxYear = currentYear + 20;

  // Check if year is within valid range
  if (year < currentYear || year > maxYear) return false;

  // If it's the current year, check if the month is valid
  if (year === currentYear) {
    const currentMonth = currentDate.getMonth() + 1; // getMonth() returns 0-11
    if (month < currentMonth) return false;
  }

  return true;
}

export const cardInfoModel = z.object({
  cardholderName: z.string().min(1).max(128),
  cardNumber: z
    .string()
    .min(1)
    .max(20)
    .regex(/^\d+$/, "Card number must be numeric")
    .refine((val) => isValidLuhn(val), {
      message: "Invalid card number",
    }),
  expiry: z
    .string()
    .regex(/^(0[1-9]|1[0-2])\/\d{2}$/, "Expiry must be in mm/yy format")
    .refine((val) => isValidExpiry(val), {
      message: "Invalid expiry date",
    }),
  cvv: z
    .string()
    .min(3)
    .max(4)
    .regex(/^\d{3,4}$/, "CVV must be 3-4 digits"),
});
export type CardInfo = z.infer<typeof cardInfoModel>;

export const paymentInfoPayloadModel = z.object({
  method: z.enum([PaymentMethod.Card]),
  cardDetails: cardInfoModel,
  productId: z.number().int(),
  orderId: z.number().int(),
});
export type PaymentInfoPayload = z.infer<typeof paymentInfoPayloadModel>;

export const paymentInfoModel = cardInfoModel.merge(
  z.object({
    id: z.number().int(),
    productId: z.number().int(),
    orderId: z.number().int(),
    createdAt: z.coerce.string(),
    updatedAt: z.coerce.string(),
  }),
);
export type PaymentInfo = z.infer<typeof paymentInfoModel>;
