package com.rc.httpcore.net

import android.os.AsyncTask
import android.os.Environment
import android.text.TextUtils
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.io.InputStream
import java.io.RandomAccessFile

/**
 * eg: http://www.download.com/projectname/dl/test.apk
 * 将文件下载到sd卡/Download目录。
 * 下载到本地的文件件名，如果没指定则为test.apk。
 *
 */
class DownloadTask(
    private val listener: DownloadListener,
    private val dlPath: String = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path,
    private var fileName: String?,
    private val headers: Map<String, String>? = null
) :
    AsyncTask<String, Int, Int>() {

    companion object {
        const val TYPE_SUCCESS: Int = 1
        const val TYPE_FAILED: Int = 2
        const val TYPE_PAUSED: Int = 3
        const val TYPE_CANCELED: Int = 4
    }

    private var isCanceled: Boolean = false
    private var isPaused: Boolean = false

    private var lastProgress: Int = 0

    override fun doInBackground(vararg params: String?): Int {
        var file: File? = null
        var inputStream: InputStream? = null
        var saveFile: RandomAccessFile? = null
        try {
            var downloadedLength = 0L
            val downloadUrl = params[0]
            downloadUrl ?: return TYPE_FAILED

            if (TextUtils.isEmpty(fileName)) {
                fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"))
            }

            file = File(dlPath, fileName!!)
            if (file.exists()) {
                downloadedLength = file.length()
            }
            val contentLength: Long = getContentLength(downloadUrl)
            if (contentLength == 0L) {
                return TYPE_FAILED
            } else if (contentLength == downloadedLength) {
                // 已经下载的字节数和文件的总字节数相等，说明已经下载完成。
                return TYPE_SUCCESS
            }
            val builder = Request.Builder()
            headers?.let {
                for ((key, value) in it)
                    builder.addHeader(key, value)
            }
            val request = builder
                // 断点下载，指定从那个字节开始下
                .addHeader("RANGE", "bytes=" + downloadedLength + "-")
                .url(downloadUrl)
                .build()
            val response = OkHttpClient()
                .newCall(request)
                .execute()

            inputStream = response.body!!.byteStream()
            saveFile = RandomAccessFile(file, "rw")
            saveFile.seek(downloadedLength) // 跳过已经下载的字节
            val buff = ByteArray(1024)
            var total = 0
            var len = 0;
            while ({ len = inputStream.read(buff);len }() != -1) {
                if (isCanceled) {
                    return TYPE_CANCELED
                } else if (isPaused) {
                    return TYPE_PAUSED
                } else {
                    total += len
                    saveFile.write(buff, 0, len)
                    // 计算已经下载的百分比
                    val progress: Int = ((total + downloadedLength) * 100 / contentLength).toInt()
                    publishProgress(progress)
                }
            }
            response.body!!.close()
            return TYPE_SUCCESS
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            try {
                inputStream?.close()
                saveFile?.close()
                if (isCanceled) file?.delete()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return TYPE_FAILED
    }

    override fun onProgressUpdate(vararg values: Int?) {
        val progress = values[0]
        progress?.let {
            if (it > lastProgress) {
                listener.onProgress(it)
                lastProgress = it
            }
        }
    }

    override fun onPostExecute(status: Int?) {
        when (status) {
            TYPE_SUCCESS -> listener.onSuccess()
            TYPE_FAILED -> listener.onFailed(null)
            TYPE_PAUSED -> listener.onPaused()
            TYPE_CANCELED -> listener.onCanceled()
            else -> Unit
        }
    }

    fun pauseDownload() {
        this.isPaused = true
    }

    fun cancelDownload() {
        this.isCanceled = true
    }

    private fun getContentLength(downloadUrl: String): Long {
        val builder = Request.Builder()
        headers?.let {
            for ((key, value) in it)
                builder.addHeader(key, value)
        }
        val request = builder.url(downloadUrl).build()
        val response = OkHttpClient()
            .newCall(request)
            .execute()
        if (response.isSuccessful) {
            val contentLength = response.body!!.contentLength()
            response.close()
            return contentLength
        }
        return 0
    }
}