export * from './specs/MultipleImagePicker.nitro'
export * from './types'

import { NitroModules } from 'react-native-nitro-modules'

import { type MultipleImagePicker } from './specs/MultipleImagePicker.nitro'

import { processColor, Appearance } from 'react-native'

import {
  PickerResult,
  Config,
  NitroConfig,
  CropResult,
  CropConfig,
  NitroCropConfig,
  PreviewConfig,
  NitroPreviewConfig,
  MediaPreview,
  CameraConfig,
  NitroCameraConfig,
  CameraResult,
  Language,
} from './types'
import { CropReject, CameraError } from './types/error'

const Picker = NitroModules.createHybridObject<MultipleImagePicker>(
  'MultipleImagePicker'
)

type IPromisePicker<T extends Config> = T['selectMode'] extends 'single'
  ? PickerResult
  : PickerResult[]

export async function openPicker<T extends Config>(
  conf: T
): Promise<IPromisePicker<T>> {
  return new Promise((resolved, rejected) => {
    const config = { ...defaultOptions, ...conf } as NitroConfig
    config.primaryColor = processColor(config.primaryColor) as any
    config.backgroundDark = processColor(config.backgroundDark) as any

    if ((config as Config)?.theme === 'system') {
      const theme = Appearance.getColorScheme() ?? 'light'
      config.theme = theme
    }

    config.language = validateLanguage(config.language)

    if (typeof config.crop === 'boolean') {
      config.crop = config.crop ? { ratio: [] } : undefined
    }

    if (config.crop) config.crop.ratio = config.crop?.ratio ?? []

    return Picker.openPicker(
      config,
      (result: PickerResult[]) => {
        resolved(result as IPromisePicker<T>)
      },
      (reject: number) => {
        rejected(reject)
      }
    )
  })
}

export async function openCropper(
  image: string,
  config?: CropConfig
): Promise<CropResult> {
  return new Promise(
    (resolved, rejected: (reason: (typeof CropReject)[0]) => void) => {
      const cropConfig = {
        presentation: 'fullScreenModal',
        language: 'system',
        ratio: [],
        ...config,
      } as NitroCropConfig

      cropConfig.language = validateLanguage(cropConfig.language)

      return Picker.openCrop(
        image,
        cropConfig,
        (result: CropResult) => {
          resolved(result)
        },
        (error: number) => {
          rejected(CropReject?.[error as 0 | 1] ?? CropReject[0])
        }
      )
    }
  )
}

export function openPreview(
  media: MediaPreview[] | PickerResult[],
  index: number = 0,
  conf?: PreviewConfig
): void {
  const config: PreviewConfig = {
    language: conf?.language ?? 'system',
    videoAutoPlay: true,
    ...conf,
  }

  if (config?.language && !LANGUAGES.includes(config.language)) {
    config.language = 'system'
  }

  if (media.length === 0) {
    throw new Error('Media is required')
  }

  return Picker.openPreview(
    media as MediaPreview[],
    index,
    config as NitroPreviewConfig,
    config?.onLongPress ?? (() => {})
  )
}

export async function openCamera(config?: CameraConfig): Promise<CameraResult> {
  return new Promise((resolved, rejected) => {
    const cameraConfig = {
      cameraDevice: 'back',
      presentation: 'fullScreenModal',
      language: 'system',
      mediaType: 'all',
      allowLocation: true,
      isSaveSystemAlbum: false,
      ...config,
    } as NitroCameraConfig

    cameraConfig.color = processColor(cameraConfig.color ?? primaryColor) as any

    cameraConfig.language = validateLanguage(cameraConfig.language)

    if (typeof cameraConfig.crop === 'boolean') {
      cameraConfig.crop = cameraConfig.crop ? { ratio: [] } : undefined
    }

    if (cameraConfig.crop && !cameraConfig.crop?.ratio)
      cameraConfig.crop.ratio = []

    return Picker.openCamera(
      cameraConfig,
      (result: CameraResult) => {
        resolved(result)
      },
      (error: CameraError) => {
        rejected(error)
      }
    )
  })
}

const DEFAULT_COUNT = 20

const validateLanguage = (language?: Language): Language => {
  if (!language || !LANGUAGES.includes(language)) {
    return 'system'
  }
  return language
}

const primaryColor = '#2979ff'

export const defaultOptions: Config = {
  maxSelect: DEFAULT_COUNT,
  maxVideo: DEFAULT_COUNT,
  primaryColor,
  backgroundDark: '#2f2f2f',
  allowedLimit: true,
  numberOfColumn: 3,
  isPreview: true,
  mediaType: 'all',
  selectedAssets: [],
  selectBoxStyle: 'number',
  selectMode: 'multiple',
  presentation: 'fullScreenModal',
  language: 'system',
  theme: 'system',
  isHiddenOriginalButton: false,
  allowSwipeToSelect: true,
  camera: {
    cameraDevice: 'back',
    videoMaximumDuration: 60,
  },
}

const LANGUAGES = [
  'system',
  'zh-Hans',
  'zh-Hant',
  'ja',
  'ko',
  'en',
  'th',
  'id',
  'vi',
  'ru',
  'de',
  'fr',
  'ar',
] as const
