/**
 * WHMCS Custom Field Utilities (domain-internal)
 */

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 [];
};

/**
 * Convert raw id value (string or number) to trimmed string key
 */
const toIdKey = (raw: unknown): string | undefined => {
  if (typeof raw === "string") return raw.trim() || undefined;
  if (typeof raw === "number") return String(raw);
  return undefined;
};

/**
 * Convert raw value to string (handles string, number, boolean)
 */
const toStringValue = (raw: unknown): string | undefined => {
  if (raw === undefined || raw === null) return undefined;
  if (typeof raw === "string") return raw;
  if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
  return undefined;
};

/**
 * Process a plain object as a field map (key-value pairs)
 */
const processPlainObjectFields = (obj: Record<string, unknown>): Record<string, string> => {
  const result: Record<string, string> = {};
  for (const [key, value] of Object.entries(obj)) {
    if (typeof value === "string") {
      const trimmedKey = key.trim();
      if (trimmedKey) result[trimmedKey] = value;
    }
  }
  return result;
};

/**
 * Process a single custom field entry and add to map
 */
const processCustomFieldEntry = (
  entry: Record<string, unknown>,
  map: Record<string, string>
): void => {
  const id = toIdKey("id" in entry ? entry["id"] : undefined);
  const name = typeof entry["name"] === "string" ? entry["name"].trim() : undefined;
  const value = toStringValue("value" in entry ? entry["value"] : undefined);

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

/**
 * 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 {};

  // Handle plain object (key-value pairs)
  if (isObject(customFields) && !Array.isArray(customFields) && !("customfield" in customFields)) {
    return processPlainObjectFields(customFields);
  }

  // Handle array or { customfield } structure
  const map: Record<string, string> = {};
  for (const entry of normalizeCustomFieldEntries(customFields)) {
    processCustomFieldEntry(entry, map);
  }
  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;
}
