package com.cr.network

import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
import com.cr.data.*
import com.cr.dialog.DialogLoadingUtil
import com.cr.dialog.DialogNormal
import com.cr.models.iNetDataModel
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.ConnectException
import java.util.concurrent.TimeUnit

/**
 * 操作系统：MAC系统
 * 创建者：王成
 * 创建日期：2023/4/8 14:39
 * 描述：网络通信
 */
class TCPDataTask {
    // define: 2023/4/10 定义显示或关闭等待条
    val PROGRESS_SHOW:Int = 1001
    val PROGRESS_CLOSE:Int = 1002
    val SHOW_MESSAGE:Int = 1003
    var DOWNLOAD_ERROR:Int = 1004
    var DOWNLOAD_PROGRESS:Int = 1005
    var DOWNLOAD_COMPLETE:Int = 1006

    // define: 2023/4/10 定义变量
    var context:Context? = null

    /**
     * 多线程管理器
     */
    private var handler: Handler = object:Handler(Looper.getMainLooper()){
        // todo: 2023/4/10 处理消息
        override fun handleMessage(msg: Message) {
            if(msg.what == PROGRESS_SHOW){
                DialogLoadingUtil.show(context!!,msg.obj.toString())
            }else if(msg.what == PROGRESS_CLOSE){
                DialogLoadingUtil.dismiss()
            }else if(msg.what == SHOW_MESSAGE){
                DialogNormal(context!!,"警告",msg.obj.toString()).show()
            }
        }
    }

    /**
     * 对外接口
     */
    interface OnChangeListener{
        fun onSuccess(jsonArray:JSONArray)
        fun onFailed(message:String)
    }

    /**
     * 下载监听
     */
    interface OnDownloadListener{
        // todo: 2023/4/12 开始下载
        fun onStart()
        // todo: 2023/4/12 下载失败
        fun onFailed(message:String)

        // todo: 2023/4/12 下载进度
        fun onProgress(progress:Int,total:Int)

        // todo: 2023/4/12 下载完成
        fun onComplete()

    }

    // todo: 2023/4/8 网络连接
    var okHttp: OkHttpClient? = null

    /**
     * 单例方法
     */
    companion object{
        fun getInstance() = InstanceHelper.self
    }

    object InstanceHelper{
        var self = TCPDataTask()
    }

    /**
     * 初始化
     * @constructor
     */
    constructor(){
        /**
         * 初始化连接
         */
        okHttp = OkHttpClient.Builder()
            .connectTimeout(6*1000,TimeUnit.MILLISECONDS)
            .readTimeout(6*1000,TimeUnit.MILLISECONDS)
            .writeTimeout(6*1000,TimeUnit.MILLISECONDS)
            .build()
    }

    /**
     * 显示等待框
     * @param message String 等待提示内容
     */
    private fun showLoading(message:String){
        var msg:Message = Message();
        msg.what = PROGRESS_SHOW
        msg.obj = message
        handler.sendMessage(msg)
    }

    /**
     * 关闭等待框
     */
    private fun dismissLoading(){
        var msg:Message = Message();
        msg.what = PROGRESS_CLOSE
        handler.sendMessage(msg)
    }

    /**
     * 显示提示消息
     * @param message String
     */
    private fun showMessage(message:String){
        var msg:Message = Message();
        msg.what = SHOW_MESSAGE
        msg.obj = message
        handler.sendMessage(msg)
    }

    /**
     *
     * @param url String 服务地址
     * @param iModel iNetDataModel<T> 发送数据
     * @param callback OnChangeListener 回调
     */
    fun<T> sendJSON(url:String, iModel:iNetDataModel<T>, callback:OnChangeListener){
        sendJSON(url,iModel,callback,null,null)
    }

    /**
     * 发送JSON数据
     * @param url String 服务地址
     * @param iModel iNetDataModel<T> 发送数据
     * @param callback OnChangeListener 回调
     * @param context Context 上下文  如果不显示等待框 可以传null
     * @param loadingMessage String 等待消息内容
     */
    fun<T> sendJSON(url:String, iModel:iNetDataModel<T>, callback:OnChangeListener,context:Context?,loadingMessage:String?){
        this.context = context
        // todo: 2023/4/8 确定传输类型
        var mediaType:MediaType = "application/json;charset=utf-8".toMediaType()
        // todo: 2023/4/8 创建数据传输内容
        var requestBody:RequestBody = iModel.toJSON().toRequestBody(mediaType)
        var request:Request = Request.Builder().url(url).post(requestBody).build()
        // todo: 2023/4/10 判断是否需要显示等待框
        if(loadingMessage != null){
            showLoading(loadingMessage)
        }
        // todo: 2023/4/8 连接发送
        okHttp?.newCall(request)?.enqueue(object :Callback{
            // todo: 2023/4/8 失败
            override fun onFailure(call: Call, e: IOException) {
                // todo: 2023/4/10 关闭等待框
                dismissLoading()
                if(e is ConnectException){
                    if(callback != null) callback.onFailed("服务器异常，连接超时！")
                }else{
                    var errMessage: String? = e.message
                    if(callback != null) callback.onFailed(errMessage!!)
                }
            }
            // todo: 2023/4/8 成功
            override fun onResponse(call: Call, response: Response) {
                // todo: 2023/4/10 关闭等待框
                dismissLoading()
                if(response.code == 200){
                    try{
                        var successMessage:String = response.body!!.string()
                        checkJSON(successMessage,callback)
                    }catch (e:java.lang.Exception){
                        if(callback != null) callback.onFailed(e.message!!)
                    }
                }
            }
        })
    }

    fun sendDownloadFile(context: Context, fullName:String, url: String, callBack:OnDownloadListener){
        if(callBack != null) callBack.onStart()
        // todo: 2023/4/12 上下文
        this.context = context
        // todo: 2023/4/12 定义下载的Url
        var request:Request = Request.Builder().url(url).build()
        // todo: 2023/4/12 开始调用下载
        okHttp?.newCall(request)?.enqueue(object:Callback{
            // todo: 2023/4/12 下载失败
            override fun onFailure(call: Call, e: IOException) {
                handler.post(Runnable {
                    if(callBack!= null) {
                        callBack.onComplete()
                        callBack.onFailed(e.message!!)
                    }
                })
            }

            // todo: 2023/4/12 下载成功
            override fun onResponse(call: Call, response: Response) {
                var inputStream:InputStream? = null
                var buf = ByteArray(2048)
                var len:Int
                var fos:FileOutputStream?=null
                try{
                    inputStream = response.body!!.byteStream()
                    var total:Long = response.body!!.contentLength()
                    var sum:Long = 0
                    // todo: 2023/4/12 创建文件
                    var file:File = File(fullName)
                    fos = FileOutputStream(file)
                    while (true){
                        len = inputStream.read(buf)
                        if(len == -1) break
                        fos.write(buf,0,len)
                        sum += len
                        handler.post(Runnable {
                            if(callBack != null) callBack.onProgress(sum.toInt(), total.toInt())
                        })
                    }
                    fos.flush()
                }catch (e: IOException){
                    handler.post(Runnable {
                        if(callBack!= null) callBack.onFailed(e.message!!)
                    })
                }finally {
                    inputStream!!.close()
                    fos!!.close()
                    handler.post(Runnable {
                        if(callBack != null) callBack.onComplete()
                    })
                }
            }

        })
    }

    /**
     * 解析JSON数据
     * @param JSON String JSON字符串
     * @param callback OnChangeListener
     */
    private fun checkJSON(JSON: String,callback:OnChangeListener) {
        val jsonObject: JSONObject
        try {
            jsonObject = JSONObject(JSON)
            val res = jsonObject.optString(RES_HEAD)
            if (res == RES_ERR_FLAG) {
                // todo: 2023/4/10 服务器返回错误消息
                val resObj = jsonObject.getJSONArray(RES_CONTENT)
                if (callback != null) callback.onFailed(
                    resObj.getJSONObject(0).optString(RES_ERR_DES)
                )
            } else if (res == RES_NULL_FLAG) {
                // todo: 2023/4/10 未获取到任何服务条件的数据
                val resObj = jsonObject.getJSONArray(RES_CONTENT)
                if (callback != null) callback.onFailed(
                    resObj.getJSONObject(0).optString(RES_ERR_DES)
                )
            } else if (res == RES_SUCCESS_FLAG) {
                // todo: 2023/4/10 正确返回
                val resObj = jsonObject.getJSONArray(RES_CONTENT)
                if (callback != null) callback.onSuccess(resObj)
            } else {
                // todo: 2023/4/10 服务器返回类型未知
                if (callback != null) callback.onFailed("服务器返回数据错误！")
            }
        } catch (ex: JSONException) {
            if (callback != null) callback.onFailed("数据解析错误！")
        }
    }
}