import { Platform } from 'react-native';
import RNFS from 'react-native-fs';
import { ensurePngFile, isPngPath, normalizePath, toPngFileName } from './pngImage';

export function hashUrl(url: string): string {
  let hash = 0;
  for (let i = 0; i < url.length; i++) {
    hash = (hash * 31 + url.charCodeAt(i)) | 0;
  }
  return Math.abs(hash).toString(36);
}

/** Resolve a local path or remote URL to a PNG local path readable by OpenCV / RNFS */
export async function resolveImageUrl(
  source: string,
  cacheFileName?: string,
): Promise<string> {
  const trimmed = source.trim();
  if (!trimmed) {
    throw new Error('Image URL is empty');
  }

  const pngCacheName = toPngFileName(
    cacheFileName ?? `img_${hashUrl(trimmed)}.png`,
  );

  if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
    const tmpDest = `${RNFS.CachesDirectoryPath}/tmp_${Date.now()}_${pngCacheName}`;
    const { statusCode } = await RNFS.downloadFile({
      fromUrl: trimmed,
      toFile: tmpDest,
    }).promise;
    if (statusCode !== 200) {
      throw new Error(`Download image failed: ${trimmed}`);
    }
    try {
      return await ensurePngFile(tmpDest, pngCacheName);
    } finally {
      if (await RNFS.exists(tmpDest)) {
        await RNFS.unlink(tmpDest);
      }
    }
  }

  const normalized = normalizePath(trimmed);
  if (await RNFS.exists(normalized) && isPngPath(normalized)) {
    return normalized;
  }

  if (normalized.startsWith('file://')) {
    return ensurePngFile(normalized, pngCacheName);
  }

  if (Platform.OS === 'ios' && normalized.startsWith('/')) {
    return ensurePngFile(normalized, pngCacheName);
  }

  if (await RNFS.exists(normalized)) {
    return ensurePngFile(normalized, pngCacheName);
  }

  // Android bundled assets: resolveAssetSource may yield asset:/ or
  // file:///android_asset/ URIs that RNFS cannot read directly.
  if (Platform.OS === 'android') {
    const assetPath = trimmed
      .replace(/^asset:\/?\/?/, '')
      .replace(/^file:\/\/\/android_asset\//, '');
    if (assetPath !== trimmed) {
      const tmpDest = `${RNFS.CachesDirectoryPath}/tmp_${Date.now()}_${pngCacheName}`;
      await RNFS.copyFileAssets(assetPath, tmpDest);
      try {
        return await ensurePngFile(tmpDest, pngCacheName);
      } finally {
        if (await RNFS.exists(tmpDest)) {
          await RNFS.unlink(tmpDest);
        }
      }
    }
  }

  return ensurePngFile(trimmed, pngCacheName);
}
