/**
 * ID Normalization Utilities
 * FE-TYPE-001: Ensure all IDs are string (UUID) not number
 *
 * Provides utilities to normalize IDs to strings (UUIDs) consistently
 * across the application, preventing type mismatches.
 */

/**
 * Normalize an ID to a string
 * Handles both string and number IDs, converting them to strings
 *
 * @param id - ID value (string, number, or undefined/null)
 * @returns Normalized string ID or undefined if input is null/undefined
 *
 * @example
 * ```typescript
 * normalizeId(123) // "123"
 * normalizeId("abc-123") // "abc-123"
 * normalizeId(null) // undefined
 * ```
 */
export function normalizeId(
  id: string | number | null | undefined,
): string | undefined {
  if (id === null || id === undefined) {
    return undefined;
  }

  if (typeof id === 'string') {
    return id;
  }

  if (typeof id === 'number') {
    return String(id);
  }

  // Fallback for any other type
  return String(id);
}

/**
 * Normalize an ID to a string (required)
 * Throws an error if ID is null or undefined
 *
 * @param id - ID value (string, number, or undefined/null)
 * @returns Normalized string ID
 * @throws Error if id is null or undefined
 *
 * @example
 * ```typescript
 * normalizeIdRequired(123) // "123"
 * normalizeIdRequired("abc-123") // "abc-123"
 * normalizeIdRequired(null) // throws Error
 * ```
 */
export function normalizeIdRequired(
  id: string | number | null | undefined,
): string {
  const normalized = normalizeId(id);
  if (normalized === undefined) {
    throw new Error('ID is required but was null or undefined');
  }
  return normalized;
}

/**
 * Normalize an array of IDs to strings
 *
 * @param ids - Array of ID values
 * @returns Array of normalized string IDs
 *
 * @example
 * ```typescript
 * normalizeIds([1, 2, "abc"]) // ["1", "2", "abc"]
 * ```
 */
export function normalizeIds(
  ids: (string | number | null | undefined)[],
): string[] {
  return ids
    .map((id) => normalizeId(id))
    .filter((id): id is string => id !== undefined);
}

/**
 * Normalize IDs in an object
 * Recursively normalizes all fields that match common ID field names
 *
 * @param obj - Object to normalize
 * @param idFields - Optional array of field names to normalize (default: common ID fields)
 * @returns New object with normalized IDs
 *
 * @example
 * ```typescript
 * normalizeObjectIds({ id: 123, user_id: 456 })
 * // { id: "123", user_id: "456" }
 * ```
 */
export function normalizeObjectIds<T extends Record<string, any>>(
  obj: T,
  idFields: string[] = [
    'id',
    'user_id',
    'track_id',
    'playlist_id',
    'conversation_id',
    'message_id',
    'sender_id',
    'creator_id',
    'created_by',
    'parent_id',
    'parent_message_id',
  ],
): T {
  if (!obj || typeof obj !== 'object') {
    return obj;
  }

  const normalized = { ...obj } as Record<string, any>;

  for (const [key, value] of Object.entries(normalized)) {
    // Normalize ID fields
    if (idFields.includes(key)) {
      normalized[key] = normalizeId(value);
    }
    // Recursively normalize nested objects
    else if (
      value &&
      typeof value === 'object' &&
      !Array.isArray(value) &&
      !(value instanceof Date)
    ) {
      normalized[key] = normalizeObjectIds(value, idFields);
    }
    // Normalize arrays of objects
    else if (
      Array.isArray(value) &&
      value.length > 0 &&
      typeof value[0] === 'object'
    ) {
      normalized[key] = value.map((item) =>
        typeof item === 'object' && item !== null
          ? normalizeObjectIds(item, idFields)
          : item,
      );
    }
  }

  return normalized as T;
}

/**
 * Normalize IDs in an array of objects
 *
 * @param items - Array of objects to normalize
 * @param idFields - Optional array of field names to normalize
 * @returns Array of objects with normalized IDs
 *
 * @example
 * ```typescript
 * normalizeArrayIds([{ id: 1 }, { id: 2 }])
 * // [{ id: "1" }, { id: "2" }]
 * ```
 */
export function normalizeArrayIds<T extends Record<string, any>>(
  items: T[],
  idFields?: string[],
): T[] {
  return items.map((item) => normalizeObjectIds(item, idFields));
}

/**
 * Type guard to check if a value is a valid ID (string or number)
 */
export function isValidId(id: unknown): id is string | number {
  return typeof id === 'string' || typeof id === 'number';
}

/**
 * Type guard to check if a value is a valid string ID
 */
export function isValidStringId(id: unknown): id is string {
  return typeof id === 'string' && id.length > 0;
}
