package com.keyboard.theme.app.keyboard.utils

import android.content.Context
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.keyboard.theme.app.keyboard.MyAppllication
import com.keyboard.theme.app.keyboard.data.Info
import com.keyboard.theme.app.keyboard.data.InfoChild
import com.keyboard.theme.app.keyboard.api.OnApplyApi
import net.sf.sevenzipjbinding.ArchiveFormat
import net.sf.sevenzipjbinding.SevenZip
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream
import net.sf.sevenzipjbinding.impl.RandomAccessFileOutStream
import org.json.JSONArray
import java.io.BufferedReader
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.io.InputStreamReader
import java.io.RandomAccessFile
import java.io.StringWriter

object FileManager {

    fun getFileStr(stream: InputStream, callback: (String?) -> Unit) {
        try {
            var leng = 0
            val writer = StringWriter()
            val charArrayOf = CharArray(stream.available())
            val reader = BufferedReader(InputStreamReader(stream))
            while (reader.read(charArrayOf).also {
                    leng = it
                } != -1) {
                writer.write(charArrayOf, 0, leng)
            }

            callback.invoke(writer.toString())

        } catch (ex: Exception) {
            callback.invoke(null)
        }

    }

    fun getDataBean(str: String): List<Info> {
        var skinList = mutableListOf<Info>()
        JSONArray(str).let {
            for (i in 0 until it.length()) {
                it.getJSONObject(i).apply {
                    val name = getString("className")
                    var skin = mutableListOf<InfoChild>()
                    getJSONArray("list").let { keyList ->
                        for (j in 0 until keyList.length()) {
                            keyList.getJSONObject(j).let { listStr ->

                                val mpreview = listStr.getString("preview")
                                val mthumb = listStr.getString("thumb")
                                val mtitle = listStr.getString("title")
                                val mzipUrl = listStr.getString("zipUrl")
                                skin.add(
                                    InfoChild(
                                        title = mtitle,
                                        thumb = mthumb,
                                        zipUrl = mzipUrl,
                                        preview = mpreview
                                    )
                                )
                            }
                        }
                    }
                    skinList.add(Info(name, skin))
                }
            }
        }
        return skinList
    }


    fun writeNewFile(input: InputStream, filePath: String): Boolean {
        var stream: FileOutputStream? = null
        var outStream: ByteArrayOutputStream? = null
        try {
            val outStream = ByteArrayOutputStream()
            val bytes = ByteArray(4096)
            var length = 0
            while (input.read(bytes).also {
                    length = it
                } != -1) {
                outStream.write(bytes, 0, length)
            }


            val file = File(filePath)
            if (!file.exists()) {
                file.createNewFile()
            }
            stream = FileOutputStream(file)
            stream.run {

                write(outStream.toByteArray())


            }
            outStream.close()
            stream.close()
            return true
        } catch (ex: Exception) {
            outStream?.close()
            stream?.close()
            return false
        }

    }


    private fun getZipName(url: String): String {
        return url.substring(url.lastIndexOf("/") + 1)

    }

    fun getUnZip(url: String): String {
        val fileName = getZipName(url)
        return fileName.substringBefore(".")
    }

    fun getZipData(title: String, url: String, con: Context, listener: OnApplyApi) {

        Glide.with(con)
            .asFile()
            .load(url)
            .addListener(object : RequestListener<File> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<File>,
                    isFirstResource: Boolean
                ): Boolean {
                    listener.applyListener(false, "")
                    return false
                }

                override fun onResourceReady(
                    resource: File,
                    model: Any,
                    target: Target<File>?,
                    dataSource: DataSource,
                    isFirstResource: Boolean
                ): Boolean {

                    val fileInputStream = FileInputStream(resource)
                    dealFile(title, url, fileInputStream, listener)
                    return false
                }

            }).preload()


    }

    private fun dealFile(
        title: String,
        url: String,
        input: FileInputStream,
        listener: OnApplyApi
    ) {
        val zipPath = "${MyAppllication.instance.cacheDir}/${title}_ZIP"
        val unPath = "${MyAppllication.instance.cacheDir}/${title}"

        val zipBoolean = writeNewFile(input, zipPath)
        val randomAccessFileInStream =
            RandomAccessFileInStream(RandomAccessFile(File(zipPath), "r"))
        val openInArchive = SevenZip.openInArchive(
            ArchiveFormat.SEVEN_ZIP,
            randomAccessFileInStream
        )

        var out: RandomAccessFileOutStream? = null

        if (zipBoolean) {
            try {
                var filePath: String = ""
                openInArchive.simpleInterface.archiveItems.forEach { item ->
                    if (!item.isFolder) {
                        val file = File(unPath, item.path)
                        out = RandomAccessFileOutStream(RandomAccessFile(file, "rw"))
                        item.extractSlow(out)
                        filePath = file.path
                    } else {
                        File(unPath, item.path).mkdirs()
                    }
                }
                listener.applyListener(true, filePath)
            } catch (ex: Exception) {
                listener.applyListener(false, "")

            } finally {
                openInArchive.close()
                randomAccessFileInStream.close()
                out?.close()
            }
        }
    }
}