import {check, PERMISSIONS, request, RESULTS} from 'react-native-permissions';
import {CameraRoll} from '@react-native-camera-roll/camera-roll';
import {Paths, File, Directory} from 'expo-file-system';
import {Image as ImageCompressor} from 'react-native-compressor';
import {tokenManager} from '@config/tokens';
import {getApiHeaders} from '@config/api';
import {getAPILevel, isIos, sentryLogs} from '@shared/utils';

export const DOWNLOAD_ERRORS = {
  GALLERY_PERMISSION_NOT_GRANTED: 'GALLERY_PERMISSION_NOT_GRANTED',
};

export const getFileExtension = (url: string): string => {
  const pathname = url.split('?')[0].split('#')[0]; // strip query/hash
  const filename = pathname.split('/').pop() ?? ''; // last path segment
  const dot = filename.lastIndexOf('.');
  return dot >= 0 ? filename.slice(dot + 1) : '';
};

const convertToJpg = (uri: string): Promise<string> => {
  return ImageCompressor.compress(uri, {
    output: 'jpg',
    compressionMethod: 'auto',
  });
};

const checkGalleryPermission = async (): Promise<boolean> => {
  if (isIos) {
    // CameraRoll package needs this permission to work correctly
    // TODO: research other alternatives to ask only for PHOTO_LIBRARY_ADD_ONLY permission
    const permission = PERMISSIONS.IOS.PHOTO_LIBRARY;
    const status = await check(permission);
    if (status === RESULTS.GRANTED || status === RESULTS.LIMITED) {
      return true;
    }
    if (status === RESULTS.DENIED) {
      const result = await request(permission);
      return result === RESULTS.GRANTED || result === RESULTS.LIMITED;
    }
    return false;
  }

  // Android 29+ (scoped storage) doesn't need explicit permission to save
  if (getAPILevel() >= 29) {
    return true;
  }

  const permission = PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE;
  const status = await check(permission);
  if (status === RESULTS.GRANTED) {
    return true;
  }
  if (status === RESULTS.DENIED) {
    const result = await request(permission);
    return result === RESULTS.GRANTED;
  }
  return false;
};

const downloadFromServer = async (
  remoteUrl: string,
  filename?: Nullable<string>,
) => {
  const dir = new Directory(Paths.cache, 'downloads_tmp');
  // The temp dir isn't guaranteed to exist across cold launches.
  if (!dir.exists) {
    dir.create({intermediates: true, idempotent: true});
  }
  // Saving a video to the camera roll requires a proper extension (e.g.
  // `.mp4`) — the asset URL is typically an API path with no extension,
  // so we pin the destination File to the original `filename` from the
  // attachment metadata. Falling back to the directory lets HTTP infer.
  let destination: File | Directory = dir;
  if (filename && filename.length > 0) {
    const destFile = new File(dir, filename);
    // `downloadFileAsync` throws "Destination already exists" if a prior
    // attempt left the file behind — e.g. `CameraRoll.saveAsset` threw
    // before the cleanup `delete()` ran. Clear it so re-downloads work.
    if (destFile.exists) {
      destFile.delete();
    }
    destination = destFile;
  }
  const token = await tokenManager.getValidAccessToken();
  const remoteFile = await File.downloadFileAsync(remoteUrl, destination, {
    headers: getApiHeaders(token),
  });
  return remoteFile;
};

export const saveAssetToGallery = async ({
  uri,
  remoteUrl,
  filename,
  type,
}: {
  uri: Nullable<string>;
  remoteUrl: string;
  filename?: Nullable<string>;
  type: 'photo' | 'video';
}) => {
  // Check permissions to gallery
  const hasPermission = await checkGalleryPermission();
  if (!hasPermission) {
    throw DOWNLOAD_ERRORS.GALLERY_PERMISSION_NOT_GRANTED;
  }

  try {
    // Check if asset exists in file system
    if (uri) {
      const file = new File(uri);
      if (file.exists) {
        try {
          if (type === 'photo') {
            // Convert to JPEG if the extensions is different from JPEG or PNG
            const extension = getFileExtension(uri);
            if (!['jpg', 'jpeg', 'png'].includes(extension)) {
              const tempImage = await convertToJpg(uri);
              await CameraRoll.saveAsset(tempImage, {type});
              return;
            }
          }

          // Default save the original file
          await CameraRoll.saveAsset(uri, {type});
          return;
        } catch (error) {
          // Catch any error, fall through to server download
          sentryLogs.warn({
            message: 'Error saving asset to gallery',
            module: 'CHATS',
            component: 'saveAssetToGallery',
            data: {
              uri,
              type,
              error: error instanceof Error ? error.message : String(error),
            },
          });
        }
      }
    }

    // Download from server as fallback
    const remoteFile = await downloadFromServer(remoteUrl, filename);
    try {
      await CameraRoll.saveAsset(remoteFile.uri, {type});
    } finally {
      // Always clear the temp file — leaving it behind would make the
      // next download attempt fail with "Destination already exists".
      remoteFile.delete();
    }
  } catch (error) {
    sentryLogs.error({
      error,
      module: 'CHATS',
      component: 'saveAssetToGallery',
      message: 'Error saving asset to gallery',
    });
    throw error;
  }
};
