package com.adealink.weparty.image.viewmodel

import android.annotation.SuppressLint
import android.content.ContentValues
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.webkit.URLUtil
import androidx.lifecycle.MutableLiveData
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.mvvm.viewmodel.BaseViewModel
import com.adealink.frame.util.AppUtil
import com.adealink.weparty.imageselect.util.PictureMimeType
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.memory.PooledByteBuffer
import com.facebook.common.memory.PooledByteBufferInputStream
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.BaseDataSubscriber
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.common.RotationOptions
import com.facebook.imagepipeline.request.ImageRequestBuilder
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import kotlin.coroutines.resumeWithException

//TODO wtr 这部分较粗糙 待整理
class ImagePreviewExtensionViewModel : BaseViewModel() {
    val saveResult = MutableLiveData<Resource<Uri>>()

    fun saveImageToAlbum(imageUri: String) {
        viewModelScope.launch {
            saveResult.postValue(Resource.loading())
            try {
                val savedUri = withContext(Dispatcher.WENEXT_THREAD_POOL) {
                    when {
                        URLUtil.isNetworkUrl(imageUri) -> handleNetworkImage(imageUri)
                        imageUri.startsWith("content://") -> handleContentUri(
                            imageUri,
                            "image",
                            "image/*"
                        )
                        imageUri.startsWith("file://") -> handleFileUri(imageUri, "image/*")
                        else -> throw IllegalArgumentException("Unsupported uri type")
                    }
                }
                saveResult.postValue(Resource.success(savedUri))
            } catch (e: Exception) {
                saveResult.postValue(Resource.error(e))
            }
        }
    }

    fun saveLocalVideoToAlbum(videoLocalUrl: String?) {
        viewModelScope.launch {
            if (videoLocalUrl == null) {
                saveResult.postValue(Resource.error(IOException("Video local url is null")))
                return@launch
            }
            saveResult.postValue(Resource.loading())
            try {
                val savedUri = withContext(Dispatcher.WENEXT_THREAD_POOL) {
                    when {
                        videoLocalUrl.startsWith("content://") -> handleContentUri(
                            videoLocalUrl,
                            "video",
                            "video/*"
                        )
                        else -> handleFileUri(videoLocalUrl, "video/*")
                    }
                }
                saveResult.postValue(Resource.success(savedUri))
            } catch (e: Exception) {
                saveResult.postValue(Resource.error(e))
            }
        }
    }

    // 处理网络图片
    private suspend fun handleNetworkImage(url: String): Uri {
        return downloadAndSaveImage(url)
    }

    private suspend fun downloadAndSaveImage(url: String): Uri =
        suspendCancellableCoroutine { cancellableContinuation ->
            val uri = Uri.parse(url)
            val imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)
                .setRotationOptions(RotationOptions.autoRotate())
                .build()

            val dataSource = Fresco.getImagePipeline().fetchEncodedImage(imageRequest, null)

            dataSource.subscribe(
                object : BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
                    override fun onNewResultImpl(dataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
                        if (!dataSource.isFinished) return

                        try {
                            val ref = dataSource.result ?: throw IOException("Empty image data")
                            val imageStream: InputStream = PooledByteBufferInputStream(ref.get())
                            val fileName = URLUtil.guessFileName(uri.toString(), null, null)
                            val savedUri = saveToGallery(imageStream, fileName, "image/*")
                            cancellableContinuation.resume(savedUri, null)
                        } catch (e: Exception) {
                            cancellableContinuation.resumeWithException(e)
                        } finally {
                            CloseableReference.closeSafely(dataSource.result)
                            dataSource.close()
                        }
                    }

                    override fun onFailureImpl(dataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
                        cancellableContinuation.resumeWithException(
                            dataSource.failureCause ?: IOException("Unknown error")
                        )
                        dataSource.close()
                    }

                    override fun onProgressUpdate(progress: DataSource<CloseableReference<PooledByteBuffer>>) {
                        // 可选：处理进度更新
                    }
                },
                CallerThreadExecutor.getInstance() // 指定回调执行线程
            )

            // 协程取消时关闭 DataSource
            cancellableContinuation.invokeOnCancellation {
                dataSource.close()
            }
        }

    // 处理 Content Uri
    private fun handleContentUri(uriString: String, namePrefix: String, mineType: String): Uri {
        val uri = Uri.parse(uriString)
        return AppUtil.appContext.contentResolver.openInputStream(uri)?.use { inputStream ->
            saveToGallery(
                inputStream = inputStream,
                displayName = getFileNameFromContentUri(uri, namePrefix),
                mineType
            )
        } ?: throw FileNotFoundException("Cannot open content uri")
    }

    // 处理文件路径
    private fun handleFileUri(uriString: String, mineType: String): Uri {
        val file = File(uriString.replace("file://", ""))
        if (!file.exists()) throw FileNotFoundException("File not exists")

        return saveToGallery(
            inputStream = FileInputStream(file),
            displayName = file.name,
            mineType
        )
    }

    // 核心保存方法（适配 Android 10+）
    @SuppressLint("Range")
    private fun saveToGallery(
        inputStream: InputStream,
        displayName: String,
        mineType: String
    ): Uri {
        val values =
            if (PictureMimeType.eqImage(mineType)) {
                ContentValues().apply {
                    put(MediaStore.Images.Media.DISPLAY_NAME, displayName)
                    put(MediaStore.Images.Media.MIME_TYPE, mineType)
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
                        put(MediaStore.Images.Media.IS_PENDING, 1)
                    }
                }
            } else {
                ContentValues().apply {
                    put(MediaStore.Video.Media.DISPLAY_NAME, displayName)
                    put(MediaStore.Video.Media.MIME_TYPE, "video/*")
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES)
                        put(MediaStore.Video.Media.IS_PENDING, 1)
                    }
                }
            }

        val resolver = AppUtil.appContext.contentResolver
        var uri: Uri? = null

        try {
            // 插入 MediaStore
            uri = resolver.insert(
                if (PictureMimeType.eqImage(mineType)) {
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                } else {
                    MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                },
                values
            ) ?: throw IOException("Failed to create media entry")

            // 写入文件内容
            resolver.openOutputStream(uri)?.use { output ->
                inputStream.copyTo(output)
            } ?: throw IOException("Failed to get output stream")

            // 适配 Android Q+
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                values.clear()
                if (PictureMimeType.eqImage(mineType)) {
                    values.put(MediaStore.Images.Media.IS_PENDING, 0)
                } else {
                    values.put(MediaStore.Video.Media.IS_PENDING, 0)
                }
                resolver.update(uri, values, null, null)
            }

            // 通知媒体扫描（兼容旧版本）
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                val path = uri.path ?: throw IOException("Invalid uri path")
                MediaScannerConnection.scanFile(
                    AppUtil.appContext,
                    arrayOf(path),
                    arrayOf(mineType),
                    null
                )
            }

            return uri
        } catch (e: Exception) {
            uri?.let { resolver.delete(it, null, null) }
            throw e
        }
    }

    // 从 Content Uri 获取文件名
    @SuppressLint("Range")
    private fun getFileNameFromContentUri(uri: Uri, namePrefix: String): String {
        return AppUtil.appContext.contentResolver.query(
            uri,
            arrayOf(MediaStore.Images.ImageColumns.DISPLAY_NAME),
            null,
            null,
            null
        )?.use { cursor ->
            if (cursor.moveToFirst()) {
                cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME))
            } else {
                "${namePrefix}_${System.currentTimeMillis()}.jpg"
            }
        } ?: "${namePrefix}_${System.currentTimeMillis()}.jpg"
    }
}

sealed class Resource<T>(
    val data: T? = null,
    val error: Throwable? = null
) {
    class Loading<T> : Resource<T>()

    class Success<T>(data: T) : Resource<T>(data = data)

    class Error<T>(error: Throwable) : Resource<T>(error = error)

    companion object {
        fun <T> loading(): Resource<T> = Loading()
        fun <T> success(data: T): Resource<T> = Success(data)
        fun <T> error(error: Throwable): Resource<T> = Error(error)
    }
}