/**
 * Shared WHMCS Provider Utilities
 * Single source of truth for WHMCS data parsing
 * 
 * Raw API types are source of truth - no fallbacks or variations expected.
 */

/**
 * Parse amount from WHMCS API response
 * WHMCS returns amounts as strings or numbers
 */
export function parseAmount(amount: string | number | undefined): number {
  if (typeof amount === "number") return amount;
  if (!amount) return 0;
  
  const cleaned = String(amount).replace(/[^\d.-]/g, "");
  const parsed = Number.parseFloat(cleaned);
  return Number.isNaN(parsed) ? 0 : parsed;
}

/**
 * Format date from WHMCS API to ISO string
 * Returns undefined if input is invalid
 */
export function formatDate(input?: string | null): string | undefined {
  if (!input) return undefined;
  
  const date = new Date(input);
  if (Number.isNaN(date.getTime())) return undefined;
  
  return date.toISOString();
}

/**
 * Normalize status using provided status map
 * Generic helper for consistent status mapping
 */
export function normalizeStatus<T extends string>(
  status: string | null | undefined,
  statusMap: Record<string, T>,
  defaultStatus: T
): T {
  if (!status) return defaultStatus;
  const mapped = statusMap[status.trim().toLowerCase()];
  return mapped ?? defaultStatus;
}

/**
 * Normalize billing cycle using provided cycle map
 * Generic helper for consistent cycle mapping
 */
export function normalizeCycle<T extends string>(
  cycle: string | null | undefined,
  cycleMap: Record<string, T>,
  defaultCycle: T
): T {
  if (!cycle) return defaultCycle;
  const normalized = cycle.trim().toLowerCase().replace(/[_\s-]+/g, " ");
  return cycleMap[normalized] ?? defaultCycle;
}

const isObject = (value: unknown): value is Record<string, unknown> =>
  typeof value === "object" && value !== null;

const normalizeCustomFieldEntries = (value: unknown): Array<Record<string, unknown>> => {
  if (Array.isArray(value)) return value.filter(isObject);
  if (isObject(value) && "customfield" in value) {
    const custom = (value as { customfield?: unknown }).customfield;
    if (Array.isArray(custom)) return custom.filter(isObject);
    if (isObject(custom)) return [custom];
    return [];
  }
  return [];
};

/**
 * Build a lightweight map of WHMCS custom field identifiers to values.
 * Accepts the documented WHMCS response shapes (array or { customfield }).
 */
export function getCustomFieldsMap(customFields: unknown): Record<string, string> {
  if (!customFields) return {};

  if (isObject(customFields) && !Array.isArray(customFields) && !("customfield" in customFields)) {
    return Object.entries(customFields).reduce<Record<string, string>>((acc, [key, value]) => {
      if (typeof value === "string") {
        const trimmedKey = key.trim();
        if (trimmedKey) acc[trimmedKey] = value;
      }
      return acc;
    }, {});
  }

  const map: Record<string, string> = {};
  for (const entry of normalizeCustomFieldEntries(customFields)) {
    const id =
      "id" in entry && entry.id !== undefined && entry.id !== null
        ? String(entry.id).trim()
        : undefined;
    const name =
      "name" in entry && typeof entry.name === "string"
        ? entry.name.trim()
        : undefined;
    const rawValue = "value" in entry ? entry.value : undefined;
    if (rawValue === undefined || rawValue === null) continue;
    const value = typeof rawValue === "string" ? rawValue : String(rawValue);
    if (!value) continue;

    if (id) map[id] = value;
    if (name) map[name] = value;
  }

  return map;
}

/**
 * Retrieve a custom field value by numeric id or name.
 */
export function getCustomFieldValue(
  customFields: unknown,
  key: string | number
): string | undefined {
  if (key === undefined || key === null) return undefined;
  const map = getCustomFieldsMap(customFields);
  const primary = map[String(key)];
  if (primary !== undefined) return primary;

  if (typeof key === "string") {
    const numeric = Number.parseInt(key, 10);
    if (!Number.isNaN(numeric)) {
      const numericValue = map[String(numeric)];
      if (numericValue !== undefined) return numericValue;
    }
  }

  return undefined;
}
