package com.ydl.ydlcommon.utils.log

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import com.ydl.ydlcommon.base.BaseApp
import com.ydl.ydlcommon.data.PlatformDataManager
import com.ydl.ydlcommon.data.http.LogParam
import com.ydl.ydlcommon.data.http.ThrowableConsumer
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.ydl.ydlcommon.utils.FileUtils
import com.yidianling.common.tools.*
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList

/**
 * @author : Zhangwenchao
 * @e-mail : zhangwch@yidianling.com
 * @time   : 2018/6/12
 */
class LogHelper private constructor() {

    companion object {
        fun getInstance(): LogHelper {
            return Holder.INSTANCE
        }
    }

    fun deleteExpireLogSync() {
        Observable.create<Any> {

            try {
                deleteExpireLog()
            } catch (e: Exception) {
            }
        }.subscribeOn(Schedulers.io())
            .subscribe()
    }

    /**
     * 删除过期日志
     */
    private fun deleteExpireLog() {
        val files = getLogFolder().listFiles()
        val calendar = Calendar.getInstance()
        calendar.add(Calendar.WEEK_OF_YEAR, -1)
        val expireDate = dateFormat.format(calendar.time).toInt()
        if (files != null && files.isNotEmpty()) {
            for (file in files) {
                val date = file.name.split("-")[1].toInt()
                if (date < expireDate) file.delete()
            }
        }
    }

    @SuppressLint("SimpleDateFormat")
    private val dateFormat = SimpleDateFormat("yyyyMMdd")
    @SuppressLint("SimpleDateFormat")
    private val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")

    fun writeLogSync(content: String) {
        val trace = Throwable().stackTrace[1]
        val className = trace.className
        val methodName = trace.methodName
        val line = trace.lineNumber
        Observable.create<Any> {
            try {
                writeLog(content, className, methodName, line)
            } catch (e: Exception) {
            }
        }.subscribeOn(Schedulers.io())
            .subscribe()
    }

    private fun writeLog(content: String, className: String, methodName: String, line: Int) {
        try {
            val fileWriter = FileWriter(getLogFile(), true)
            val writer = BufferedWriter(fileWriter)
            writer.write("""Time:${format.format(Calendar.getInstance().time)}""")
            writer.newLine()
            writer.write("UserInfo:uid = ${ModularServiceManager.getPlatformUserService()?.getUser()?.userId}")
            writer.newLine()
            writer.write("""Network:${RxNetTool.getNetWorkTypeName(BaseApp.getApp())}""")
            writer.newLine()
            writer.write("""DevicesInfo:${RxDeviceTool.getBuildBrandModel()},${RxDeviceTool.getSDKVersionName()}""")
            writer.newLine()
            writer.write("""VersionInfo:${RxAppTool.getAppVersionName(BaseApp.getApp())}""")
            writer.newLine()
            writer.write("ClassName:$className")
            writer.newLine()
            writer.write("MethodName:$methodName")
            writer.newLine()
            writer.write("Line:$line")
            writer.newLine()
            writer.write("LogInfo:$content")
            writer.newLine()
            writer.write("--------")
            writer.newLine()
            writer.flush()
            writer.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }


    @SuppressLint("CheckResult")
    fun uploadLog(showToast: Boolean) {
        Observable.create<File> {
            it.onNext(zip())
            it.onComplete()
        }.subscribeOn(Schedulers.io())
            .flatMap {
                PlatformDataManager.getHttp().uploadLog(
                    LogParam(
                        it
                    )
                )
            }
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(Consumer {
                if (showToast) {
                    ToastUtil.toastShort(it.msg)
                }
                Log.d("TAG", "")
            }, object : ThrowableConsumer() {
                override fun accept(msg: String) {
                    if (showToast) {
                        ToastUtil.toastShort(msg)
                    }
                    Log.d("TAG", msg)
                }
            })

    }


    private fun zip(): File {

        val files = ArrayList<File>()

        //zip生成日志文件夹
        val zipFile = File(getLogFolder().parentFile, "NewYdlApp.zip")

        //app日志
        val appLog = File(getLogFolder().absolutePath)
        //云信日志
        val yunxinLog = getYunXinLog(BaseApp.getApp())
        //声网日志
        val agoraLog = getAgoraLog(BaseApp.getApp())
        val agoraRtmLog = getAgoraRTMLog(BaseApp.getApp())
        val agoraRtmBackLog = getAgoraRtmBackLog(BaseApp.getApp())

        if (zipFile.exists()) zipFile.delete()
        zipFile.createNewFile()

        if (appLog.exists()) {
            files.add(appLog)
        }
        if (yunxinLog.exists()) {
            files.add(yunxinLog)
        }
        if (agoraLog.exists()) {
            files.add(agoraLog)
        }
        if (agoraRtmLog.exists()) {
            files.add(agoraRtmLog)
        }
        if (agoraRtmBackLog.exists()) {
            files.add(agoraRtmBackLog)
        }

//        ZipUtils.toZip(getLogFolder().absolutePath, FileOutputStream(zipFile), true)
        ZipUtils.toZip(files, FileOutputStream(zipFile))
        return zipFile
    }

/*    private fun zip() {
        val zipFile = File(getLogFolder().parentFile, "NewYdlApp.zip")
        if (zipFile.exists()) zipFile.delete()
        zipFile.createNewFile()
        val zos = GZIPOutputStream(FileOutputStream(zipFile))
        val fis = FileInputStream(getLogFolder())
        val buffer = ByteArray(1024)
        var len = -1
        len = fis.read(buffer)
        while (len != -1) {
            zos.write(buffer, 0, len)
            len = fis.read(buffer)
        }
        zos.close()
        fis.close()
    }*/


    private fun getLogFile(): File {
        val date = dateFormat.format(Calendar.getInstance().time)
        val name = "${ModularServiceManager.getPlatformUserService()?.getUser()?.userId}-$date"
        val folder = getLogFolder()
        val file = File(folder, name)
        if (!file.exists() || !file.isFile) {
            file.createNewFile()
        }
        return file
    }


    //获取app运行日志文件夹
    private fun getLogFolder(): File {
        val cacheDir = BaseApp.getApp().externalCacheDir.absolutePath
        val logFolder = File(cacheDir, "log")
        if (!logFolder.exists() || !logFolder.isDirectory) {
            logFolder.mkdir()
        }
        val folder = File(logFolder, "NewYdlApp")
        if (!folder.exists() || !folder.isDirectory) {
            folder.mkdir()
        }
        return folder
    }

    //获取云信日志路径
    private fun getYunXinLog(context: Context): File {
        val yunxin = FileUtils.getSDDirectory() + "/" + context.packageName + "/nim/log"
        LogUtil.d(yunxin)
        return File(yunxin)
    }

    //获取声网日志
    private fun getAgoraLog(context: Context): File {
//        val agora = FileUtils.getSDDirectory() + "/" + context.packageName + "/agorasdk.log"

        val filePath = context.getExternalFilesDir(null).path + "/agorasdk.log"

        return File(filePath)
    }


    //获取RTM日志
    private fun getAgoraRTMLog(context: Context): File {
        val agoraRTMLog = FileUtils.getSDDirectory() + "/" + context.packageName + "/agorartm.log"
        return File(agoraRTMLog)
    }

    //获取RTM备份日志
    private fun getAgoraRtmBackLog(context: Context): File {
        val agoraRTMLog = FileUtils.getSDDirectory() + "/" + context.packageName + "/agorartm_1.log"
        return File(agoraRTMLog)
    }


    private object Holder {
        val INSTANCE = LogHelper()
    }

}