import { DigitFieldOpts } from "@/types/common";
import { z } from "zod";

export function digitField(opts: DigitFieldOpts) {
  const {
    min,
    max = min,
    required = false,
    invalidTypeError = `Must be a ${min}${
      min === max ? "" : `–${max}`
    } digit number`,
  } = opts;

  let schema = z.coerce
    .string({ invalid_type_error: invalidTypeError })
    .trim()
    .refine(
      (val) =>
        val.match(/^\d+$/) !== null && val.length >= min && val.length <= max,
      {
        message:
          min === max
            ? `Must be exactly ${min} digits`
            : `Must be between ${min} and ${max} digits`,
      }
    );
  // 3) transform to number
  // .transform((val) => Number(val));

  return required ? schema : schema.optional();
}

const emailBase = z
  .string({ required_error: "Email is required" })
  .trim()
  .email("Invalid email address");

const phoneBase = z.coerce
  .string({ invalid_type_error: "Must be a phone number" })
  .trim()
  .regex(/^\d{10}$/, "Must be exactly 10 digits")
  .transform(Number);

export function emailField(opts: { required?: boolean } = {}) {
  return opts.required
    ? emailBase.nonempty({
        message: "Email is required",
      })
    : emailBase.optional();
}

export const phoneField = (opts: { required?: boolean } = {}) =>
  digitField({
    min: 10,
    required: opts.required,
    invalidTypeError: "Must be a phone number",
  });

export const asNumberOrUndef = (val: unknown) => {
  if (typeof val === "number") return Number.isFinite(val) ? val : undefined;
  if (typeof val === "string") {
    const s = val.trim();
    if (s === "") return undefined;
    const n = Number(s);
    return Number.isFinite(n) ? n : undefined;
  }
  return undefined;
};

type NumberFieldOptions = {
  required?: boolean;
  int?: boolean;
  defaultValue?: number;
  message?: string;
};

export const numberField = ({
  required = false,
  int = false,
  defaultValue,
  message = "This field is required",
}: NumberFieldOptions = {}) => {
  let base = z.number({
    required_error: message,
    invalid_type_error: message,
  });

  if (int) {
    base = base.int();
  }

  let finalSchema: z.ZodTypeAny = base;

  if (!required) {
    finalSchema = base.optional();

    if (defaultValue !== undefined) {
      finalSchema = finalSchema.default(defaultValue);
    }
  }

  return z.preprocess(asNumberOrUndef, finalSchema);
};
