import * as FileSystemLegacy from 'expo-file-system/legacy';


const getCacheDir = (): string => {
  const baseDir = FileSystemLegacy.documentDirectory ?? FileSystemLegacy.cacheDirectory;
  if (!baseDir) {
    throw new Error('No writable file system directory is available for image caching.');
  }
  return `${baseDir}plant-images/`;
};

const ensureCacheDir = async (): Promise<string> => {
  const cacheDir = getCacheDir();
  const dirInfo = await FileSystemLegacy.getInfoAsync(cacheDir);
  if (!dirInfo.exists) {
    await FileSystemLegacy.makeDirectoryAsync(cacheDir, { intermediates: true });
  }
  return cacheDir;
};

const hashString = (value: string): string => {
  // FNV-1a 32-bit hash for stable cache file names.
  let hash = 2166136261;
  for (let index = 0; index < value.length; index += 1) {
    hash ^= value.charCodeAt(index);
    hash = Math.imul(hash, 16777619);
  }
  return (hash >>> 0).toString(36);
};

const getDataUriExtension = (uri: string): string => {
  const mimeMatch = uri.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,/i);
  const mimeType = mimeMatch?.[1]?.toLowerCase() || '';

  if (mimeType.includes('png')) return 'png';
  if (mimeType.includes('webp')) return 'webp';
  if (mimeType.includes('gif')) return 'gif';
  if (mimeType.includes('heic')) return 'heic';
  if (mimeType.includes('heif')) return 'heif';
  return 'jpg';
};

const getUriExtension = (uri: string): string => {
  const cleanPath = uri.split(/[?#]/)[0];
  const extensionMatch = cleanPath.match(/\.([a-zA-Z0-9]+)$/);
  return extensionMatch?.[1]?.toLowerCase() || 'jpg';
};

const getFileName = (uri: string): string => {
  const extension = uri.startsWith('data:')
    ? getDataUriExtension(uri)
    : getUriExtension(uri);
  return `${hashString(uri)}.${extension}`;
};

export const ImageCacheService = {
  /**
   * Check if an image is already cached locally.
   */
  isCached: async (uri: string): Promise<{ exists: boolean; localUri: string }> => {
    const cacheDir = await ensureCacheDir();
    const fileName = getFileName(uri);
    const localUri = `${cacheDir}${fileName}`;
    const info = await FileSystemLegacy.getInfoAsync(localUri);
    return { exists: info.exists, localUri };
  },

  /**
   * Cache an image (base64 data URI or remote URL) and return the local file path.
   */
  cacheImage: async (uri: string): Promise<string> => {
    const cacheDir = await ensureCacheDir();

    const fileName = getFileName(uri);
    const localUri = `${cacheDir}${fileName}`;
    const info = await FileSystemLegacy.getInfoAsync(localUri);
    const exists = info.exists;
    if (exists) return localUri;

    if (uri.startsWith('data:')) {
      // Extract base64 content after the comma
      const base64Data = uri.split(',')[1];
      if (!base64Data) throw new Error('Invalid base64 data URI');
      await FileSystemLegacy.writeAsStringAsync(localUri, base64Data, {
        encoding: FileSystemLegacy.EncodingType.Base64,
      });
    } else if (/^(file:\/\/|content:\/\/)/i.test(uri)) {
      await FileSystemLegacy.copyAsync({ from: uri, to: localUri });
    } else {
      // Remote URL - download it
      const downloadResult = await FileSystemLegacy.downloadAsync(uri, localUri);
      if (downloadResult.status !== 200) {
        throw new Error(`Failed to download image: HTTP ${downloadResult.status}`);
      }
    }

    return localUri;
  },

  /**
   * Delete a cached image by its local path.
   */
  deleteCachedImage: async (localUri: string): Promise<void> => {
    try {
      const info = await FileSystemLegacy.getInfoAsync(localUri);
      if (info.exists) {
        await FileSystemLegacy.deleteAsync(localUri, { idempotent: true });
      }
    } catch (e) {
      console.error('Failed to delete cached image', e);
    }
  },
};
