package com.ypsx.yppos.http.repository.request

import com.ypsx.base.base.appContext
import com.ypsx.base.network.AppException
import com.ypsx.base.util.LogUtils
import com.ypsx.base.util.PathUtils
import com.ypsx.base.util.dXLog
import com.ypsx.yppos.http.apiService
import com.ypsx.yppos.http.data.bean.*
import com.ypsx.yppos.http.data.entity.OrderStatusEnum
import com.ypsx.yppos.http.data.entity.PosCommandType
import com.ypsx.yppos.http.data.entity.PosPayMethod
import com.ypsx.yppos.http.data.entity.PosStatus
import com.ypsx.yppos.http.data.request.*
import com.ypsx.yppos.room.database.PosDatabase
import com.ypsx.yppos.room.database.name
import com.ypsx.yppos.room.entity.PosProduct
import com.ypsx.yppos.room.repository.PosConfigRepository
import com.ypsx.yppos.room.repository.PosProductRepository
import com.ypsx.yppos.ui.popup.PayAmountPopupWindow
import com.ypsx.yppos.utils.*
import kotlinx.coroutines.delay
import java.io.File

val HttpRequestCoroutine: HttpRequestManger by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
    HttpRequestManger()
}

class HttpRequestManger {

    /**
     * 申请注册
     */
    suspend fun applyPos(applyPosMachineRequest: ApplyPosMachineRequest): ApiResponse<PosMachineResponse> {
        //清除数据
        CacheUtil.setUpdateTimeBigger("")
        CacheUtil.setLoginResponse(null)
        PosDatabase.clearAllTables()
        val applyPosData = apiService.applyPos(applyPosMachineRequest)
        if (applyPosData.isSuccess()) {
            val id = applyPosData.data
            //根据POS机Id查询POS机详情
            return apiService.getById(id)
        } else {
            //抛出错误异常
            throw AppException(applyPosData.code, applyPosData.message)
        }
    }

    /**
     * 注册并登陆
     */
    suspend fun getById(id: String): ApiResponse<PosMachineResponse> {
        val registerData = apiService.getById(id)
        //判断注册结果 注册成功，调用登录接口
        return if (registerData.isSuccess()) {
            val posId = registerData.data.id
            val status = registerData.data.status
            //如果在申请中，延时2秒继续获取详情
            if (status == PosStatus.APPLY.name) {
                delay(2000)
                getById(posId)
            } else {
                LogUtils.debugInfo("status")
                registerData
            }
        } else {
            throw AppException(registerData.code, registerData.message)
        }
    }

    /**
     * 用户登录并获取配置，获取商品信息
     */
    suspend fun posLogin(
        posId: String,
        storeId: String,
        username: String,
        password: String
    ): ApiResponse<LoginResponse> {
        val loginRequest = PosLoginRequest(storeId, username, password, posId)
        val loginData = apiService.posLogin(loginRequest)
        if (loginData.isSuccess()) {
            val data = loginData.data
            //保存登录信息
            CacheUtil.setLoginResponse(data)
            val posConfigData = apiService.getByPosId(posId)
            if (posConfigData.isSuccess()) {
                val configData = posConfigData.data
                //保存到数据库
                PosConfigRepository.getInstance().savePosConfig(posId, configData)
                val askTime = CacheUtil.getUpdateTimeBigger()
                val currentTime = DateUtil.getTodayDateTime()
                //增量获取商品信息
                val productList = apiService.getProductList(storeId, askTime)
                if (productList.isSuccess()) {
                    PosProductRepository.getInstance().insertAll(productList.data)
                    //更新时间
                    CacheUtil.setUpdateTimeBigger(currentTime)
                    return loginData
                } else {
                    throw AppException(productList.code, productList.message)
                }
            } else {
                throw AppException(posConfigData.code, posConfigData.message)
            }
        } else {
            throw AppException(loginData.code, loginData.message)
        }

    }

    /**
     * 创建订单
     */
    suspend fun createOrder(
        insertOrderRequest: InsertOrderRequest,
        authCode: String,
        payMethod: PosPayMethod
    ): UploadOrderResponse {
        val list = arrayListOf(insertOrderRequest)
        //上传订单
        val uploadOrderData = apiService.uploadOrder(list)
        if (uploadOrderData.isSuccess()) {

            val uploadData = uploadOrderData.data
            if (uploadData.isNotEmpty()) {
                val data = uploadData[0]
                val success = data.success
                if (success) {
                    if (payMethod == PosPayMethod.CASHPAY) {
                        data.payMethod = payMethod.name
                        return data
                    }
                    var cardPayPassword: String? = null
                    if (payMethod == PosPayMethod.CARDPAY) {
                        cardPayPassword = ""
                    }
                    val unifiedCashPaySignRequest =
                        UnifiedCashPaySignRequest(
                            authCode,
                            data.orderId,
                            payMethod.name,
                            total = insertOrderRequest.payAmount,
                            cardPayPassword = cardPayPassword
                        )
                    //获得对应的支付订单签名
                    val cashPaySignData = apiService.getCashPaySign(unifiedCashPaySignRequest)
                    if (cashPaySignData.isSuccess()) {
                        data.total = insertOrderRequest.payAmount
                        data.authCode = authCode
                        data.payMethod = payMethod.name
                        return data
                    } else {
                        throw AppException(cashPaySignData.code, cashPaySignData.getResponseMsg())
                    }
                } else {
                    throw AppException(1, data.errorMessage)
                }
            } else {
                throw AppException(1, "数据解析失败")
            }

        } else {
            throw AppException(uploadOrderData.code, uploadOrderData.message)
        }
    }

    /**
     * 获取订单状态
     */
    suspend fun getOrderStatusById(orderId: String): ApiResponse<OrderStatusResponse> {
        val orderStatusData = apiService.getOrderStatusById(orderId)
        if (orderStatusData.isSuccess()) {
            when (orderStatusData.data.status) {
                OrderStatusEnum.CREATED.name -> {
                    if (PayAmountPopupWindow.state) {
                        throw AppException(100001, "支付超时")
                    } else {
                        delay(2000)
                        return getOrderStatusById(orderId)
                    }
                }
                OrderStatusEnum.PAYFAILED.name, OrderStatusEnum.CANCELED.name, OrderStatusEnum.REJECTED.name -> {
                    throw AppException(1, "支付失败")
                }
                else -> {
                    return orderStatusData
                }
            }
        } else {
            throw AppException(orderStatusData.code, orderStatusData.message)
        }

    }

    /**
     * 根据命令，上传日志或数据库
     */
    suspend fun uploadLog(posCode: String) {
        val commandByPosCode = apiService.getCommandByPosCode(posCode)
        if (commandByPosCode.isSuccess()) {
            val data = commandByPosCode.data
            if (data.isNotEmpty()) {
                for (commandResponse in data) {
                    replyCommand(commandResponse.id)
                    val startTime = System.currentTimeMillis()
                    when (commandResponse.type) {
                        //上传日志文件
                        PosCommandType.UPLOAD_LOG.name -> {
//压缩文件
                            var todayDate = DateUtil.getTodayDate()
                            if (commandResponse.parameters != todayDate) {
                                todayDate = commandResponse.parameters
                            }
                            val upLoadUrl = PathUtils.getUpLoadUrl(todayDate)
                            if (upLoadUrl.isNullOrEmpty()) {
                                return
                            }
                            //获取压缩地址
                            val zipUrl: String = PathUtils.getZipUrl(todayDate, ".zip")
                            val currentTimeMillis = System.currentTimeMillis()
                            var zipFiles =
                                com.blankj.utilcode.util.ZipUtils.zipFiles(upLoadUrl, File(zipUrl))
                            var millis = System.currentTimeMillis() - currentTimeMillis
                            LogUtils.debugInfo("压缩使用${millis}s")

                            saveCommand(zipUrl, startTime, commandResponse)


                        }
                        //上传数据库
                        PosCommandType.UPLOAD_DB.name -> {
                            val databasePath = appContext.getDatabasePath(name)
                            val currentTimeMillis = System.currentTimeMillis()
                            val zipUrl: String =
                                PathUtils.getZipUrl(commandResponse.id.toString(), ".zip")
                            var zipFiles =
                                com.blankj.utilcode.util.ZipUtils.zipFiles(
                                    arrayListOf(databasePath),
                                    File(zipUrl)
                                )
                            val millis = System.currentTimeMillis() - currentTimeMillis
                            LogUtils.debugInfo("压缩使用${millis}s")
                            saveCommand(zipUrl, startTime, commandResponse)
                        }
                        else -> {
                        }
                    }
                }
            }
            delay(1000 * 60 * 5)
            return uploadLog(posCode)
        } else {
            throw AppException(commandByPosCode.code, commandByPosCode.message)
        }
    }

    /**
     * 保护命令
     */
    private suspend fun saveCommand(
        zipUrl: String,
        startTime: Long,
        commandResponse: SimplePosCommandResponse
    ) {
        var baseUrl: String = ""
        var objectKey: String? = null
        try {
            baseUrl = OSSClientUtil.getInstance().getBaseUrl()
            objectKey = OSSClientUtil.getInstance().getObjectKey(zipUrl)
            var upload = OSSClientUtil.getInstance().upload(objectKey, zipUrl)
            val path = "$baseUrl$objectKey"
            val elapsedTimeInSeconds =
                (System.currentTimeMillis() - startTime) / 1000
            val saveCommandResultRequest = SaveCommandResultRequest(
                commandResponse.id,
                elapsedTimeInSeconds,
                path,
                true
            )
            val saveCommandResult =
                apiService.saveCommandResult(saveCommandResultRequest)
//            LogUtils.debugInfo(saveCommandResult.toJson())

        } catch (e: Exception) {
            "图片上传失败".dXLog()
        } finally {
            File(zipUrl).delete()
        }
    }

    /**
     * 回复命令
     */
    private suspend fun replyCommand(id: Long) {

        var replyCommand =
            apiService.replyCommand(ReplyCommandListRequest(arrayListOf<String>(id.toString())))
    }

    /**
     * 同步商品
     */
    suspend fun syncProduct(storeId: String) {
        val updateTimeBigger = CacheUtil.getUpdateTimeBigger()
        val todayDateTime = DateUtil.getTodayDateTime()
        val productData = apiService.getProductList(storeId, updateTimeBigger)
        if (productData.isSuccess()) {
            val data = productData.data
            PosProductRepository.getInstance().insertAll(data)
            CacheUtil.setUpdateTimeBigger(todayDateTime)
            delay(1000 * 60 * 3)
            syncProduct(storeId)
        }
    }

    suspend fun syncProducts(storeId: String) :ApiResponse<List<PosProduct>>{
        val updateTimeBigger = CacheUtil.getUpdateTimeBigger()
        val todayDateTime = DateUtil.getTodayDateTime()
        val productData = apiService.getProductList(storeId, updateTimeBigger)
        if (productData.isSuccess()) {
            val data = productData.data
            CacheUtil.setUpdateTimeBigger(todayDateTime)
            PosProductRepository.getInstance().insertAll(data)
            return productData
        }
        throw  AppException(productData.code, productData.message)

    }


}