import * as ExpoImagePicker from 'expo-image-picker';
import {pick, types} from '@react-native-documents/picker';
import {CHAT_MAX_ATTACHMENTS} from '@modules/chats/constants';
import {MediaEntity, MediaType} from '@modules/chats/interfaces';
import {normalizeMediaExtension} from '@modules/chats/utils';
import {getUlid} from '@shared/utils';

import {useMediaPermissions} from './useMediaPermissions';

export type SelectImageProps = {
  multiple: boolean;
  withVideo?: boolean;
  selectionLimit?: number;
};

export type SelectMediaResult = {
  ok: boolean;
  isPermissionDenied?: boolean;
  shouldOpenSettings?: boolean;
  data?: MediaEntity[];
};

export const useSelectMedia = () => {
  const {requestGalleryPermission, requestFilesPermission} =
    useMediaPermissions();

  /**
   * Select images and videos from the gallery. It handles the gallery permission and the image resizing.
   * @returns The selected images and videos
   */
  const selectMedia = async ({
    multiple,
    withVideo,
    selectionLimit = CHAT_MAX_ATTACHMENTS,
  }: SelectImageProps): Promise<SelectMediaResult> => {
    const {isAvailable, shouldOpenSettings} = await requestGalleryPermission();

    if (!isAvailable) {
      return {
        ok: false,
        isPermissionDenied: true,
        shouldOpenSettings,
      };
    }

    const result = await ExpoImagePicker.launchImageLibraryAsync({
      mediaTypes: withVideo ? ['images', 'videos'] : 'images',
      allowsMultipleSelection: multiple,
      selectionLimit,
      quality: 1, // no compression — our pipeline handles it
      videoExportPreset: ExpoImagePicker.VideoExportPreset.Passthrough,
      allowsEditing: false,
      orderedSelection: true,
      // Use "current" to avoid transcoding on iOS — pass the file as-is
      preferredAssetRepresentationMode:
        ExpoImagePicker.UIImagePickerPreferredAssetRepresentationMode.Current,
    });

    if (result.canceled) {
      return {ok: false};
    }

    const results = result.assets.map(asset => {
      const isVideo = asset.type === 'video';

      return {
        id: getUlid(),
        type: isVideo ? MediaType.VIDEO : MediaType.IMAGE,
        status: 'creatingAsset',
        contentType: asset.mimeType ?? (isVideo ? 'video/mp4' : 'image/jpeg'),
        localUri: asset.uri,
        height: asset.height,
        width: asset.width,
        sizeInBytes: asset.fileSize ?? 0,
        name: normalizeMediaExtension(
          asset.fileName,
          isVideo ? 'video' : 'image',
        ),
        fileAsset: null,
        ...(isVideo &&
          asset.duration != null && {
            metadata: {
              // duration is in ms already
              durationInMs: asset.duration,
            },
          }),
      } as MediaEntity;
    });

    return {
      ok: true,
      data: results,
    };
  };

  /**
   * Select a file from the device. It handles the file permission and the file picking.
   * @returns The selected file
   */
  const selectFile = async (): Promise<SelectMediaResult> => {
    const {isAvailable, shouldOpenSettings} = await requestFilesPermission();

    if (!isAvailable) {
      return {
        ok: false,
        isPermissionDenied: false,
        shouldOpenSettings,
      };
    }

    try {
      const selectedFiles = await pick({
        type: [
          types.pdf,
          types.zip,
          types.csv,
          types.doc,
          types.docx,
          types.json,
          types.plainText,
          types.ppt,
          types.pptx,
          types.xls,
          types.xlsx,
          types.images,
        ],
        allowMultiSelection: false,
      });
      const selectedFile = selectedFiles[0];

      const result: MediaEntity = {
        id: getUlid(),
        type: MediaType.FILE,
        fileAsset: null,
        status: 'idle',
        contentType: selectedFile.type || '',
        localUri: selectedFile.uri,
        sizeInBytes: selectedFile.size || 0,
        name: selectedFile.name || `media.${selectedFile.type?.split('/')[1]}`,
      };

      return {
        ok: true,
        data: [result],
      };
    } catch (error) {
      return {
        ok: false,
        data: [],
      };
    }
  };

  return {selectMedia, selectFile};
};
