import {ImageSourcePropType} from 'react-native';
import {ImageSource} from 'expo-image';

export const extractUriFromSource = (
  source: ImageSourcePropType | ImageSource,
): string | undefined => {
  if (!source) {
    return undefined;
  }

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

  if (typeof source === 'number') {
    return undefined;
  }

  if ('uri' in source && typeof source.uri === 'string') {
    return source.uri;
  }

  if (Array.isArray(source) && source.length > 0) {
    return extractUriFromSource(source[0]);
  }

  return undefined;
};

/**
 * ExpoImage `cacheKey` derivation.
 *
 * Two competing requirements:
 *  1. Different sized variants of the same image MUST land on different
 *     cache entries — a 150 px avatar already in cache shouldn't mask the
 *     "original" gallery variant of the same asset.
 *  2. The same image with a refreshed token / expires signature MUST hit
 *     the existing cache entry. Auth params change every time the
 *     bearer token rotates; if they ended up in the cache key, every
 *     re-render after a token refresh would miss cache and re-fetch
 *     the same bytes from the CDN.
 *
 * So we strip the query string down to a whitelist of "shape-defining"
 * params (currently just `width` / `height`) and sort them for stable
 * ordering. Anything else — `token`, `expires`, signature, tracking
 * params — is dropped from the key (the actual fetch URL still carries
 * them; only the cache lookup uses this trimmed key).
 */
const CACHE_KEY_PARAMS = new Set(['width', 'height']);

export const getCacheKey = (url?: Nullable<string>): string | undefined => {
  if (!url) return undefined;
  const qIndex = url.indexOf('?');
  if (qIndex === -1) return url;
  const base = url.slice(0, qIndex);
  const query = url.slice(qIndex + 1);
  // Strip the fragment if present so it doesn't leak into the last param.
  const hashIndex = query.indexOf('#');
  const params = (hashIndex === -1 ? query : query.slice(0, hashIndex)).split(
    '&',
  );
  const kept = params
    .filter(p => {
      if (!p) return false;
      const eqIdx = p.indexOf('=');
      const key = eqIdx === -1 ? p : p.slice(0, eqIdx);
      return CACHE_KEY_PARAMS.has(key);
    })
    .sort();
  return kept.length === 0 ? base : `${base}?${kept.join('&')}`;
};
