/**
 * WHMCS Zod Schema Primitives (domain-internal)
 *
 * Coercing schema helpers for WHMCS API responses.
 * WHMCS (PHP) is loosely typed — fields documented as strings may arrive
 * as numbers (and vice-versa). These primitives absorb that inconsistency
 * at the parsing boundary so the rest of the codebase sees clean types.
 */

import { z } from "zod";

/**
 * Coercing string — accepts string or number, always outputs string.
 * Use for any WHMCS response field that should be a string.
 */
export const whmcsString = z.coerce.string();

/**
 * Accepts number or string (e.g. "123"), keeps the raw union type.
 * Use when downstream code handles both types (e.g. IDs you'll parse later).
 */
export const whmcsNumberLike = z.union([z.number(), z.string()]);

/**
 * Accepts boolean, number (0/1), or string ("true"/"false"/etc).
 * Use for WHMCS boolean flags that arrive in varying formats.
 */
export const whmcsBooleanLike = z.union([z.boolean(), z.number(), z.string()]);

/**
 * Coercing required number — accepts number or numeric string, always outputs number.
 * Use for WHMCS fields that must be a number but may arrive as a string.
 */
export const whmcsRequiredNumber = z.preprocess(value => {
  if (typeof value === "number") return value;
  if (typeof value === "string" && value.trim().length > 0) {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : value;
  }
  return value;
}, z.number());

/**
 * Coercing optional number — accepts number, numeric string, null, undefined, or empty string.
 * Returns undefined for missing/empty values.
 * Use for WHMCS fields that are optional numbers but may arrive as strings.
 */
export const whmcsOptionalNumber = z.preprocess((value): number | undefined => {
  if (value === undefined || value === null || value === "") return undefined;
  if (typeof value === "number") return value;
  if (typeof value === "string") {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : undefined;
  }
  return undefined;
}, z.number().optional());

// ---------------------------------------------------------------------------
// Boolean coercion helpers
// ---------------------------------------------------------------------------

/**
 * Coerce a WHMCS boolean-like value to a real boolean.
 *
 * Truthy: `true`, `1`, `"1"`, `"true"`, `"yes"`, `"on"`
 * Everything else → `false`
 */
function toBool(value: unknown): boolean {
  if (typeof value === "boolean") return value;
  if (typeof value === "number") return value === 1;
  if (typeof value === "string") {
    const n = value.trim().toLowerCase();
    return n === "1" || n === "true" || n === "yes" || n === "on";
  }
  return false;
}

/**
 * Coercing required boolean — accepts boolean, number (0/1), or string, always outputs boolean.
 * Use for WHMCS boolean flags that must resolve to true/false.
 */
export const whmcsBoolean = z.preprocess(toBool, z.boolean());

/**
 * Coercing optional boolean — accepts boolean, number, string, null, or undefined.
 * Returns `undefined` for null/undefined, coerces everything else to boolean.
 * Use for WHMCS boolean flags that may be absent.
 */
export const whmcsOptionalBoolean = z.preprocess((value): boolean | undefined => {
  if (value === undefined || value === null) return undefined;
  return toBool(value);
}, z.boolean().optional());
