package com.duolebo.blyrobot.data

import android.content.Context
import android.os.Environment
import android.util.Log
import com.duolebo.appbase.AppBaseHandler
import com.duolebo.appbase.IAppBaseCallback
import com.duolebo.appbase.IProtocol
import com.duolebo.blyrobot.protocol.ApkReportProtocol
import com.duolebo.blyrobot.util.AdbUtil
import com.duolebo.blyrobot.util.AppUtil
import com.duolebo.blyrobot.util.Config
import net.gotev.uploadservice.UploadNotificationConfig
import net.gotev.uploadservice.ftp.FTPUploadRequest
import org.json.JSONObject
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList


class Task : IAppBaseCallback {

    private val TAG = "Task"

    lateinit var apkInfo: ApkInfo
    // 截图存放路径
    private lateinit var imagePath: String
    // 抓包存放路径
    private var capturePath = Environment
            .getExternalStorageDirectory().absolutePath + "/capture.txt"

    private var channelIndex = 0

    private var reportProtocol: ApkReportProtocol
    private var dataHandler:AppBaseHandler
    private lateinit var reportJson: JSONObject

    private var context: Context
    private val imageDateFormat = SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.CHINA)
    var proc: Process? = null

    constructor(context: Context) {
        this.context = context
        this.reportProtocol = ApkReportProtocol(context, Config.instance)
        this.dataHandler = AppBaseHandler(this)
    }

    fun from(apkInfo: ApkInfo) {
        this.apkInfo = apkInfo
//        this.imagePath = this.context.cacheDir.absolutePath + "/" + apkInfo.packageName
        this.imagePath = Environment
                .getExternalStorageDirectory().absolutePath + "/" + apkInfo.packageName
        val dir = File(this.imagePath)
        if (!dir.exists())
            dir.mkdirs()
    }

    fun start() {
        this.reportJson = JSONObject()
        this.launchApp()
        this.processChannels()
        this.uploadImage()
        this.report()
    }

    private fun finish(result: Boolean) {
        AdbUtil.stopApp(this.apkInfo.packageName)
        this.taskListener?.run {
            onComplete(result)
        }
    }

    private fun launchApp(reset: Boolean = false) {
        Log.i(TAG, "launchApp")
        if (reset) {
            try {
                AdbUtil.resetApp(this.apkInfo.packageName)
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }

        AdbUtil.launchApp("${this.apkInfo.packageName}/${this.apkInfo.launcher}")
        Thread.sleep(this.apkInfo.launchDelay * 1000L)
    }

    private fun processChannels() {
        Log.i(TAG, "processChannels")
        step()
        for (i in 1..this.apkInfo.channelCount) {
            // 模拟按键事件. 切换频道进行抓取
            this.channelIndex = i
            AdbUtil.sendMultiKey(this.apkInfo.channelKeyEvent)
            step()
        }
    }

    private fun step() {
        capture()
        // 截图保存
        val screenShots = saveScreenShot()
        val playUrlItems = analysisCapture()
    }

    // 抓包处理
    private fun capture() {
        Log.i(TAG, "capture")
        val file = File(this.capturePath)
        if (file.exists())
            file.delete()
        Thread(Runnable {
            proc = AdbUtil.tcpCapture(this.capturePath)
        }).start()
        Log.i(TAG, "capture sleep ${this.apkInfo.captureDelay} seconds")
        Thread.sleep(this.apkInfo.captureDelay * 1000L)
        proc?.destroy()
        AdbUtil.killTcpdump()
        Thread.sleep(2000L)
    }

    // 分析http抓包文件
    private fun analysisCapture(): ArrayList<PlayInfo> {
        val playUrlItems = ArrayList<PlayInfo>()
        val file = File(Environment
                .getExternalStorageDirectory().absolutePath + "/capture.txt")
        val lines = file.readLines()

        var partUrl = ""
        var timeStr = ""
        val tagGet = "GET /"
        lines.forEach {
            if (it.contains("IP (")) {
                val end = it.indexOf('.')
                timeStr = it.substring(0, end)
            }

            if (it.contains(tagGet)) {
                val start = it.indexOf(tagGet) + tagGet.length - 1
                val end = it.lastIndexOf(' ')
                partUrl = it.substring(start, end)
            }

            if (it.contains("Host")) {
                val start = it.indexOf(' ') + 1
                val host = it.substring(start)
                val url = "http://$host$partUrl"

                var add = true
                // 如果筛选url不为空，这里需要进行过滤
                if (!this.apkInfo.filterUrl.isNullOrEmpty()) {
                    if (url.contains(this.apkInfo.filterUrl))
                        add = false
                }

                if (add) {
                    // 这里进行媒体视频播放地址识别
                    val extArr = this.apkInfo.mediaExt.split("|")
                    for (ext in extArr) {
                        if (url.contains(ext)) {
                            add = true
                            break
                        }
                    }
                }

                if (add) {
                    val item = PlayInfo()
                    item.url = url
                    item.time = timeStr

                    playUrlItems.add(item)
                }

                partUrl = ""
            }
        }

        return playUrlItems
    }

    // 截取一张频道图+一张显示频道节目的图
    private fun saveScreenShot(): ArrayList<String> {
        val screenImages = ArrayList<String>()

        var time = imageDateFormat.format(Date())
        val absName = this.imagePath + "/${this.apkInfo.packageName}_${channelIndex}_$time"
        screenShot(absName)
        screenImages.add("$absName.jpg")

        AdbUtil.sendMultiKey(this.apkInfo.menuKeyEvent)
        time = imageDateFormat.format(Date())
        val absOkName = this.imagePath + "/${this.apkInfo.packageName}_${channelIndex}_${time}_ok"
        screenShot(absOkName)
        screenImages.add("$absOkName.jpg")

        return screenImages
    }

    // 截图处理，转成jpg
    private fun screenShot(absName : String) {
        val pngPath = "$absName.png"
        val jpgPath = pngPath.replace(".png", ".jpg")
        AdbUtil.screenShot(pngPath)
        // png转换成jpg
        AppUtil.pngToJpg(pngPath, jpgPath)
    }

    private fun uploadImage() {
        try {
            val uploadRequest = FTPUploadRequest(context, "ftp.duolebo.com", 21)
                    .setUsernameAndPassword("user", "password")
                    .setNotificationConfig(UploadNotificationConfig())
                    .setMaxRetries(4)

            val dir = File(imagePath)
            dir.listFiles().forEach {
                uploadRequest.addFileToUpload(it.absolutePath, "/remote/path")
            }

            val uploadId = uploadRequest.startUpload()
            Log.i(TAG, "upload id $uploadId")
        } catch (exc: Exception) {
            Log.e("AndroidUploadService", exc.message, exc)
        }

    }

    private fun report() {
        reportProtocol.execute(dataHandler)
    }

    override fun onProtocolFailed(p0: IProtocol?) {
        finish(false)
    }

    override fun onHttpFailed(p0: IProtocol?) {
        finish(false)
    }

    override fun onProtocolSucceed(p0: IProtocol?) {
        finish(true)
    }


    var taskListener: OnTaskListener? = null

    interface OnTaskListener {
        fun onComplete(result: Boolean)
    }

    class PlayInfo {
        var time = ""
        var url = ""
    }

}