package com.colorful.keyboard.theme.myutil

import android.content.Context
import android.os.AsyncTask
import net.sf.sevenzipjbinding.ExtractAskMode
import net.sf.sevenzipjbinding.ExtractOperationResult
import net.sf.sevenzipjbinding.IArchiveExtractCallback
import net.sf.sevenzipjbinding.IInArchive
import net.sf.sevenzipjbinding.ISequentialOutStream
import net.sf.sevenzipjbinding.PropID
import net.sf.sevenzipjbinding.SevenZip
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream
import okio.IOException
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.io.RandomAccessFile
import java.net.URL

interface OnDownloadListener {
    fun onDownloadComplete(isDownloaded: Boolean)
}
class ResourceDownloadUtil(private val context: Context) {
    private val destinationFolder = context.filesDir.absolutePath

    // 声明回调接口变量
    private var downloadListener: OnDownloadListener? = null

    // 设置回调监听器
    fun setOnDownloadListener(listener: OnDownloadListener) {
        this.downloadListener = listener
    }

    fun downloadAndExtractResources(zipUrl: String): Boolean {
        var isDownload = false
        val childString = getFileNameFromUrl(zipUrl)
        val file = File(destinationFolder, removeFileExtension(childString))
        var getSubDirectories = ""
        if (file.exists() && file.isDirectory) {
            getSubDirectories = getSubDirectories(file)[0]
        }
        val sub = removeFileExtension(childString) + "/" + getSubDirectories
        val subFile = File(destinationFolder, sub)
        if (!subFile.exists()) {
            // 创建 DownloadAndExtractTask 时传递回调接口的实例
            DownloadAndExtractTask(context, zipUrl, object : OnDownloadListener {
                override fun onDownloadComplete(isDownloaded: Boolean) {
                    // 下载完成后的处理操作
                    // 例如：更新界面、通知用户下载完成等
                    downloadListener?.onDownloadComplete(isDownload)
                }
            }).execute()
        } else {
            isDownload = true
            downloadListener?.onDownloadComplete(isDownload)
        }
        return isDownload
    }

    private inner class DownloadAndExtractTask(
        private val context: Context,
        url: String,
        private val callback: OnDownloadListener
    ) :
        AsyncTask<Void, Void, Boolean>() {

        private val zipUrl = url

        override fun doInBackground(vararg params: Void?): Boolean {
            return try {
                downloadZipFile()
                extractZipFile()
                true
            } catch (e: Exception) {
                e.printStackTrace()
                false
            }
        }

        override fun onPostExecute(result: Boolean) {
            // 下载解压完成后，触发回调
            callback.onDownloadComplete(result)
        }

        private fun downloadZipFile() {
            val url = URL(zipUrl)
            val connection = url.openConnection()
            connection.connect()

            val childString = getFileNameFromUrl(zipUrl)
            val input = BufferedInputStream(url.openStream())
            val outputFile = File(destinationFolder, childString)
            val outputStream = FileOutputStream(outputFile)

            val data = ByteArray(1024)
            var count: Int
            while (input.read(data, 0, 1024).also { count = it } != -1) {
                outputStream.write(data, 0, count)
            }

            outputStream.flush()
            outputStream.close()
            input.close()
        }

        private fun extractZipFile() {
            val childString = getFileNameFromUrl(zipUrl)
            val newChildString = removeFileExtension(childString)

            val zipFilePath = "$destinationFolder/$childString"
            val destDirectory = "$destinationFolder/$newChildString"

            extract7z(zipFilePath, destDirectory)
        }
    }

    fun extract7z(archivePath: String, outputPath: String) {

        val archiveFile = File(archivePath)

        if (!archiveFile.exists()) {
            return
        }

        val raf = RandomAccessFile(archiveFile, "r")
        val inStream = RandomAccessFileInStream(raf)

        val outputDir = File(outputPath)

        if (!outputDir.exists()) {
            outputDir.mkdirs()
        }


        SevenZip.openInArchive(null, inStream).use { inArchive ->
            val extractCallback = ArchiveExtractCallback(outputDir, inArchive)
            inArchive.extract(null, false, extractCallback)
        }
    }

    private class ArchiveExtractCallback(
        private val outputDir: File,
        private val inArchive: IInArchive
    ) : IArchiveExtractCallback {
        override fun getStream(index: Int, extractAskMode: ExtractAskMode?): ISequentialOutStream {
            val relativeFilePath = getOriginalFileName(index)
            val outputFile = File(outputDir, relativeFilePath)

            // Create parent directories if they don't exist
            outputFile.parentFile?.let { parent ->
                if (!parent.exists()) {
                    parent.mkdirs()
                }
            }

            return SequentialOutStream(outputFile.absolutePath)
        }


        private fun getOriginalFileName(index: Int): String {
            return inArchive.getStringProperty(index, PropID.PATH)
        }

        override fun prepareOperation(extractAskMode: ExtractAskMode?) {
            // Implement if needed
        }

        override fun setOperationResult(extractOperationResult: ExtractOperationResult?) {
            // Implement if needed
        }

        override fun setTotal(total: Long) {
            // Implement if needed
        }

        override fun setCompleted(complete: Long) {
            // Implement if needed
        }
    }

    private class SequentialOutStream(private val fileName: String) : ISequentialOutStream {
        override fun write(data: ByteArray): Int {
            try {
                val fileOutputStream = File(fileName).outputStream()
                fileOutputStream.write(data)
                fileOutputStream.close()
                return data.size
            } catch (e: IOException) {
                e.printStackTrace()
            }
            return 0
        }
    }
}