package de.wechselbild.wallpaper

import android.app.Activity
import android.content.Intent
import android.net.Uri
import androidx.activity.result.ActivityResult
import app.tauri.annotation.ActivityCallback
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
import app.tauri.plugin.Invoke
import app.tauri.plugin.JSArray
import app.tauri.plugin.JSObject
import app.tauri.plugin.Plugin
import java.io.File
import java.util.UUID
import java.util.concurrent.Executors

@InvokeArg
class SettingArgs { lateinit var name: String; var value: Boolean = false }

@InvokeArg
class IntervalArgs { var minutes: Int = 0 }

@InvokeArg
class GalleryArgs { var offset: Int = 0; var limit: Int = 48 }

@InvokeArg
class DeleteImageArgs { lateinit var id: String }

@InvokeArg
class DeleteImagesArgs { var ids: Array<String> = emptyArray() }

@InvokeArg
class ImageCropArgs {
  lateinit var id: String
  lateinit var mode: String
  var zoom: Double = 1.0
  var positionX: Double = 0.5
  var positionY: Double = 0.5
  var rotation: Int = 0
}

@InvokeArg
class ImmichConnectArgs { lateinit var serverUrl: String; lateinit var apiKey: String }

@InvokeArg
class ImmichAssetsArgs { var albumId: String? = null; var page: Int = 1; var size: Int = 30 }

@InvokeArg
class ImmichImportArgs { var ids: Array<String> = emptyArray() }

@TauriPlugin
class WallpaperPlugin(private val activity: Activity) : Plugin(activity) {
  private val io = Executors.newSingleThreadExecutor()

  @Command fun getState(invoke: Invoke) {
    if (WallpaperStore.enabled(activity)) runCatching { WallpaperRotationService.start(activity) }
    io.execute { invoke.resolve(WallpaperStore.state(activity)) }
  }

  @Command fun getGallery(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(GalleryArgs::class.java)
      invoke.resolve(WallpaperStore.gallery(activity, args.offset, args.limit))
    } catch (error: Exception) { invoke.reject(error.message ?: "Galerie konnte nicht geladen werden") }
  }

  @Command fun selectImages(invoke: Invoke) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
      addCategory(Intent.CATEGORY_OPENABLE)
      type = "image/*"
      putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
      addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
    }
    startActivityForResult(invoke, intent, "selectedImages")
  }

  @Command fun deleteImage(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(DeleteImageArgs::class.java)
      if (!WallpaperStore.delete(activity, args.id)) throw IllegalArgumentException("Bild wurde nicht gefunden")
      invoke.resolve(WallpaperStore.state(activity))
    } catch (error: Exception) { invoke.reject(error.message ?: "Bild konnte nicht gelöscht werden") }
  }

  @Command fun getImageIds(invoke: Invoke) = io.execute {
    val ids = JSArray().apply { WallpaperStore.imageIds(activity).forEach { put(it) } }
    invoke.resolve(JSObject().apply { put("ids", ids) })
  }

  @Command fun deleteImages(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(DeleteImagesArgs::class.java)
      if (WallpaperStore.deleteMany(activity, args.ids.toList()) == 0) throw IllegalArgumentException("Keine Bilder gefunden")
      invoke.resolve(WallpaperStore.state(activity))
    } catch (error: Exception) { invoke.reject(error.message ?: "Bilder konnten nicht gelöscht werden") }
  }

  @Command fun setImageCrop(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(ImageCropArgs::class.java)
      val image = WallpaperStore.setCrop(activity, args.id, args.mode, args.zoom, args.positionX, args.positionY, args.rotation)
        ?: throw IllegalArgumentException("Bild wurde nicht gefunden")
      invoke.resolve(image)
    } catch (error: Exception) { invoke.reject(error.message ?: "Bildausschnitt konnte nicht gespeichert werden") }
  }

  @ActivityCallback
  fun selectedImages(invoke: Invoke, result: ActivityResult) {
    if (result.resultCode != Activity.RESULT_OK) { invoke.reject("Bildauswahl abgebrochen"); return }
    val uris = mutableListOf<Uri>()
    result.data?.data?.let(uris::add)
    result.data?.clipData?.let { clip -> for (i in 0 until clip.itemCount) uris.add(clip.getItemAt(i).uri) }
    if (uris.isEmpty()) { invoke.reject("Keine Bilder ausgewählt"); return }
    io.execute {
      try {
        uris.forEach { uri ->
          val type = activity.contentResolver.getType(uri)
          val extension = when (type) { "image/png" -> "png"; "image/webp" -> "webp"; else -> "jpg" }
          val target = File(WallpaperStore.directory(activity), "${System.currentTimeMillis()}-${UUID.randomUUID()}.$extension")
          activity.contentResolver.openInputStream(uri).use { input -> requireNotNull(input) { "Bild konnte nicht geöffnet werden" }; target.outputStream().use(input::copyTo) }
        }
        invoke.resolve(WallpaperStore.state(activity))
      } catch (error: Exception) { invoke.reject(error.message ?: "Bilder konnten nicht importiert werden") }
    }
  }

  @Command fun setSetting(invoke: Invoke) {
    try {
      val args = invoke.parseArgs(SettingArgs::class.java)
      WallpaperStore.set(activity, args.name, args.value)
      invoke.resolve(WallpaperStore.state(activity, includePreviews = false))
    } catch (error: Exception) { invoke.reject(error.message ?: "Einstellung konnte nicht gespeichert werden") }
  }

  @Command fun setInterval(invoke: Invoke) {
    try {
      val args = invoke.parseArgs(IntervalArgs::class.java)
      WallpaperStore.setInterval(activity, args.minutes)
      if (args.minutes > 0) WallpaperRotationService.restart(activity) else WallpaperRotationService.stop(activity)
      invoke.resolve(WallpaperStore.state(activity, includePreviews = false))
    } catch (error: Exception) { invoke.reject(error.message ?: "Wechselintervall konnte nicht gespeichert werden") }
  }

  @Command fun nextWallpaper(invoke: Invoke) = io.execute {
    try {
      if (WallpaperStore.applyNext(activity)) invoke.resolve(WallpaperStore.state(activity))
      else invoke.reject("Kein verfügbares Bild konnte angewendet werden")
    } catch (error: Exception) { invoke.reject(error.message ?: "Das Hintergrundbild konnte nicht geändert werden") }
  }

  @Command fun getImmichConnection(invoke: Invoke) = io.execute {
    invoke.resolve(ImmichClient.connection(activity))
  }

  @Command fun connectImmich(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(ImmichConnectArgs::class.java)
      invoke.resolve(ImmichClient.connect(activity, args.serverUrl, args.apiKey))
    } catch (error: Exception) { invoke.reject(error.message ?: "Immich-Verbindung fehlgeschlagen") }
  }

  @Command fun disconnectImmich(invoke: Invoke) = io.execute {
    invoke.resolve(ImmichClient.disconnect(activity))
  }

  @Command fun getImmichAlbums(invoke: Invoke) = io.execute {
    try { invoke.resolve(ImmichClient.albums(activity)) }
    catch (error: Exception) { invoke.reject(error.message ?: "Immich-Alben konnten nicht geladen werden") }
  }

  @Command fun getImmichAssets(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(ImmichAssetsArgs::class.java)
      invoke.resolve(ImmichClient.assets(activity, args.albumId, args.page, args.size))
    } catch (error: Exception) { invoke.reject(error.message ?: "Immich-Bilder konnten nicht geladen werden") }
  }

  @Command fun importImmichAssets(invoke: Invoke) = io.execute {
    try {
      val args = invoke.parseArgs(ImmichImportArgs::class.java)
      invoke.resolve(ImmichClient.importAssets(activity, args.ids.toList()))
    } catch (error: Exception) { invoke.reject(error.message ?: "Immich-Bilder konnten nicht importiert werden") }
  }

  @Command fun getImmichImportProgress(invoke: Invoke) {
    invoke.resolve(ImmichClient.importProgress())
  }
}
