package http.client.retrofit

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import http.HttpClient
import http.client.LabClient
import http.exception.AICheckException
import http.exception.NetException
import http.vo.CommonDataResponse
import http.vo.CommonResponse
import http.vo.CommonRowsResponse
import http.vo.request.*
import http.vo.response.*
import io.reactivex.rxjava3.core.Observable
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import xn.xxp.room.bean.LabConfig
import xn.xxp.room.bean.NoticeSummary
import java.io.File

open class LabRetrofit : LabClient {

    private val apiService by lazy {
        HttpClient.createRetrofitApi(ApiService::class.java)
    }

    /**
     * 登录获取token
     */
//    override fun authOneLogin(param: AccessTokenReq): Observable<Boolean> {
//        return apiService.authOneLogin(param)
//            .map { response ->
//                requireSuccess(response)
//
//                HttpClient.token = response.data?.access_token
//                return@map !HttpClient.token.isNullOrEmpty()
//            }
//    }

    /**
     * 查询APK版本
     *
     * @param param 设备版本信息
     */
    override fun apkVersion(param: ApkInfoReq): Observable<ApkInfoResp> {
        val filters = mutableMapOf<String, String>().apply {
            put("core", param.code)
            put("deviceNo", param.deviceNo)
            put("version", param.version)
        }
        return apiService.apkVersion(filters)
            .map(this::dataConvert)
    }

    /**
     * 实验室信息
     *
     * @param id 设备唯一编码
     */
    override fun laboratoryInfo(id: String): Observable<LaboratoryVo> {
        return apiService.laboratoryInfo(id)
            .map(this::dataConvert)
    }

    /**
     * 危险源信息
     *
     * @param param 实验室Id、分页信息
     */
    override fun hazardlist(param: HazardReq): Observable<List<LabHazardVo>> {
        return apiService.hazardlist(param.subId, param.pageNum, param.pageSize)
            .map(this::dataConvert)
    }

    /**
     * 签到验证（进入）
     *
     * @param eBoard 是否为电子信息牌
     * @param subId 实验室id
     * @param username 学生卡编号/人员id
     */
    override fun signInCheck(
        eBoard: Boolean,
        subId: String,
        username: String
    ): Observable<SignInCheckResp> {
        val observable = if (eBoard) {
            apiService.signInXxpCheck(subId, username)
        } else {
            apiService.signInCheck(subId, username)
        }
        return observable.map(this::dataConvert)
    }

    /**
     * 签到提交-人脸验证
     */
    override fun signInFace(code: String, faceFeature: SignInReq?): Observable<String> {
        return apiService.signInFace(code, faceFeature)
            .map(this::dataConvert)
    }

    /**
     * 签到-安全准入检测三合一
     *
     * @param patrolSign 是否为巡查签到
     */
    override fun checkInAll(patrolSign: Boolean, param: CheckInAllReq): Observable<Boolean> {
        val fileBody = RequestBody.create(
            "application/octet-stream".toMediaTypeOrNull(),
            param.file
        )
        val filePart = MultipartBody.Part.createFormData("file", param.file.name, fileBody)

        val formMediaType = "multipart/form-data".toMediaTypeOrNull()
        val bodyPartMap = mutableMapOf<String, RequestBody>()
        if (!param.id.isNullOrEmpty()) {
            bodyPartMap["id"] = RequestBody.create(formMediaType, param.id)
        }
        if (!param.subId.isNullOrEmpty()) {
            bodyPartMap["subId"] = RequestBody.create(formMediaType, param.subId)
        }
        if (!param.subName.isNullOrEmpty()) {
            bodyPartMap["subName"] = RequestBody.create(formMediaType, param.subName)
        }

        val observable = if (patrolSign) {
            apiService.checkInXxpAll(bodyPartMap, filePart)
        } else {
            apiService.checkInAll(bodyPartMap, filePart)
        }
        return observable.map { response ->
            if (!response.isSuccess()) {
                throw AICheckException(response.code, response.message, response.data)
            }

            return@map true
        }
    }

    /**
     * 签到提交
     */
    override fun signIn(id: String): Observable<Boolean> {
        return apiService.signIn(id)
            .map(this::simpleConvert)
    }

    /**
     * 签到提交-有跳过安全准入检测时使用
     */
    override fun signInJump(id: String, code: String): Observable<Boolean> {
        return apiService.signInJump(id, code)
            .map(this::simpleConvert)
    }

    /**
     * 签到验证（离开）
     *
     * @param eBoard 是否为电子信息牌
     * @param subId 实验室id
     * @param username 学生卡编号/人员id
     */
    override fun signOutCheck(
        eBoard: Boolean,
        subId: String,
        username: String
    ): Observable<SignInCheckResp> {
        val observable = if (eBoard) {
            apiService.signOutXXpCheck(subId, username)
        } else {
            apiService.signOutCheck(subId, username)
        }
        return observable.map(this::dataConvert)
    }

    /**
     * 离开提交
     */
    override fun signOut(code: String): Observable<Boolean> {
        return apiService.signOut(code)
            .map(this::simpleConvert)
    }

    /**
     * 获取实验室一体机可控制设备
     *
     * @param subId 实验室id
     */
    override fun controllerList(subId: String): Observable<List<LotDeviceVo>> {
        val param = LotDeviceReq().apply { subjectId = subId }
        return apiService.controllerList(param)
            .map(this::dataConvert)
    }

    /**
     * 控制设备
     *
     * @param param 设备编号、命令
     */
    override fun sendControllerCMD(param: ControllerCMD): Observable<Boolean> {
        return apiService.sendControllerCMD(param.id, param.command)
            .map(this::simpleConvert)
    }

    /**
     * 实验室测点功能列表（首页-左侧看板）
     *
     * @param subId 实验室id
     */
    override fun functionList(subId: String): Observable<List<LabBulletinBoardVo>> {
        return apiService.functionList(subId)
            .map(this::dataConvert)
    }

    /**
     * 实验室预警测点
     *
     * @param subId 实验室id
     */
    override fun warnList(subId: String): Observable<List<LabWarnVo>> {
        return apiService.warnList(subId)
            .map { response ->
                requireSuccess(response)

                return@map response.data!!.map { item ->
                    item.triggerList = Gson().fromJson<List<LabWarnVo.TriggerVo>>(
                        item.triggerUploadData,
                        object : TypeToken<List<LabWarnVo.TriggerVo>>() {}.type
                    )
                    item
                }
            }
    }

    /**
     * 人脸比对
     */
    override fun faceCompare(param: FaceCompareReq): Observable<Boolean> {
        return apiService.faceCompare(param)
            .map(this::simpleConvert)
    }

    /**
     * 心跳
     *
     * @param num 设备唯一编码
     */
    override fun heartbeat(num: String): Observable<Boolean> {
        return apiService.heartbeat(num)
            .map(this::simpleConvert)
    }

    /**
     * 查询实验室安全制度列表
     *
     * @param type 1:学校制度 2:学院制度 3: 中心制度
     */
    override fun safeBookList(type: String): Observable<List<SafeBook>> {
        return apiService.safeBookList(type)
            .map(this::dataConvert)
    }

    /**
     * 获取实验室安全制度详细信息
     */
    override fun safeBookDetail(id: String): Observable<SafeBook> {
        return apiService.safeBookDetail(id)
            .map(this::dataConvert)
    }

    /**
     * 一体机查询危化品
     */
    override fun hazardBookList(): Observable<List<HazardBook>> {
        return apiService.hazardBookList()
            .map(this::recordsConvert)
    }

    /**
     * 获取危化品安全技术说明书详细信息
     */
    override fun hazardBookDetail(id: String): Observable<HazardBook> {
        return apiService.hazardBookDetail(id)
            .map(this::dataConvert)
    }

    /**
     * 查询实验室在线人员
     */
    override fun onlineUser(param: OnLineUserReq): Observable<CommonRowsResponse<LabPersonVo>> {
        return apiService.onlineUser(param)
            .map(this::responseConvert)
    }

    /**
     * 实验室安全整改信息
     */
    override fun checkMachineMsgList(subId: String): Observable<List<CheckMachineVo>> {
        val param = SubIdReq().apply { this.subId = subId }
        return apiService.checkMachineMsgList(param)
            .map(this::recordsConvert)
    }

    /**
     * 实验室文化图
     */
    override fun bannerImages(param: BannerImageReq): Observable<List<BannerImageBean>> {
        return apiService.bannerImages(param)
            .map(this::dataConvert)
    }

    /**
     * 文字转语音
     */
    override fun textParseVideo(text: String): Observable<SpeakInfo> {
        return apiService.textParseVideo("50", "20", text)
            .map { response ->
                requireSuccess(response)

                val data = response.data
                if ("0" != data?.result) {
                    throw NetException("1000", "转换异常")
                }
                return@map data
            }
    }

    /**
     * 物联控制权限验证
     */
    override fun lotInCheck(subId: String, username: String): Observable<String> {
        return apiService.lotInCheck(subId, username)
            .map(this::dataConvert)
    }

    /**
     * 查询实验室配置
     */
    override fun queryLabConfig(deviceNum: String): Observable<LabConfig> {
        return apiService.queryLabConfig(deviceNum)
            .map(this::dataConvert)
    }

    /**
     * 查询首页头部信息
     */
    override fun homeTopInfo(labId: String): Observable<HomeTopResp> {
        return apiService.homeTopInfo(labId)
            .map(this::dataConvert)
    }

    /**
     * 查询首页中部信息
     */
    override fun homeMiddleInfo(labId: String): Observable<HomeMiddleResp> {
        return apiService.homeMiddleInfo(labId)
            .map(this::dataConvert)
    }

    /**
     * 查询首页右侧人员信息
     */
    override fun homeRightInfo(labId: String): Observable<HomeRightResp> {
        return apiService.homeRightInfo(labId)
            .map(this::dataConvert)
    }

    /**
     * 实验室介绍
     */
    override fun labIntro(labId: String): Observable<String> {
        return apiService.labIntro(labId)
            .map(this::dataConvert)
    }

    /**
     * 查询值班人员列表
     */
    override fun dutyUserList(labId: String, startTime: String): Observable<DutyPersonVo> {
        return apiService.dutyUserList(labId, startTime)
            .map(this::dataConvert)
    }

    /**
     * 查询实验人员列表
     */
    override fun signUserList(labId: String): Observable<List<LabPersonVo>> {
        return apiService.signUserList(labId)
            .map(this::dataConvert)
    }

    /**
     * 查询准入人员列表
     */
    override fun securityUserList(
        labId: String,
        pageNumber: Int,
        pageSize: Int
    ): Observable<List<LabPersonVo>> {
        return apiService.securityUserList(labId, pageNumber, pageSize)
            .map(this::dataConvert)
    }

    /**
     * 查询巡查人员列表
     */
    override fun inspectUserList(labId: String, startTime: String): Observable<DutyPersonVo> {
        return apiService.inspectUserList(labId, startTime)
            .map(this::dataConvert)
    }

    /**
     * 视频监控
     */
    override fun cameraBySubjectId(
        labId: String,
        userId: String,
        userName: String,
        source: Int
    ): Observable<List<MonitorVo>> {
        val param = MonitorReq().apply {
            subIds = listOf(labId)
            this.userId = userId
            this.userName = userName
            this.source = source
        }
        return apiService.cameraBySubjectId(param)
            .map(this::recordsConvert)
    }

    /**
     * 获取准入人员的指纹信息列表
     */
    override fun getFingerList(labId: String): Observable<List<UserFingerVo>> {
        return apiService.getFingerList(labId)
            .map(this::dataConvert)
    }

    /**
     * 根据用户查询指纹列表
     */
    override fun getFingerByUserId(labId: String, userId: String): Observable<List<UserFingerVo>> {
        return apiService.getFingerByUserId(labId, userId)
            .map(this::dataConvert)
    }

    /**
     * 指纹录入
     */
    override fun addUserFinger(param: UserFingerVo): Observable<Boolean> {
        return apiService.addUserFinger(param)
            .map(this::simpleConvert)
    }

    /**
     * 删除指纹
     */
    override fun deleteFingerById(id: String): Observable<Boolean> {
        return apiService.deleteFingerById(id)
            .map(this::simpleConvert)
    }

    /**
     * 获取人像特征值
     */
    override fun faceFeature(file: File): Observable<String> {
        val fileBody = RequestBody.create("application/octet-stream".toMediaTypeOrNull(), file)
        val filePart = MultipartBody.Part.createFormData("file", file.name, fileBody)
        return apiService.faceFeature(filePart)
            .map(this::dataConvert)
    }

    /**
     * 人脸识别
     */
    override fun multiFaceDetection(param: AuthFaceReq): Observable<UserVo> {
        return apiService.multiFaceDetection(param)
            .map(this::dataConvert)
    }

    /**
     * 刷卡验证
     */
    override fun cardValidate(labId: String, cardNum: String): Observable<UserVo> {
        return apiService.cardValidate(labId, cardNum)
            .map(this::dataConvert)
    }

    /**
     * 密码验证
     */
    override fun pwdValidate(param: AuthPwdReq): Observable<UserVo> {
        return apiService.pwdValidate(param.num, param.labId, param.userId, param.pwd)
            .map(this::dataConvert)
    }

    /**
     * 校园卡是否能开启门禁
     */
    override fun getCardIsOpen(labId: String, cardNum: String): Observable<UserVo> {
        return apiService.getCardIsOpen(labId, cardNum)
            .map(this::dataConvert)
    }

    /**
     * 巡查签到
     */
    override fun signInWithPatrol(param: PatrolSignInReq): Observable<Boolean> {
        return apiService.signInWithPatrol(param)
            .map(this::simpleConvert)
    }

    /**
     * 巡查签退
     */
    override fun signOutWithPatrol(labId: String, userId: String): Observable<Boolean> {
        return apiService.signOutWithPatrol(labId, userId)
            .map(this::simpleConvert)
    }

    /**
     * 巡查签退/准入签退判断
     *  true-巡查 false-准入
     */
    override fun isSignInType(labId: String, userId: String): Observable<Boolean> {
        return apiService.isSignInType(labId, userId)
            .map { response ->
                requireSuccess(response)
                return@map "1" == response.data
            }
    }

    /**
     * 巡查签到前置校验
     */
    override fun signInCheckWithPatrol(labId: String, userId: String): Observable<Boolean> {
        return apiService.signInCheckWithPatrol(labId, userId)
            .map(this::simpleConvert)
    }

    /**
     * 滚动消息列表
     */
    override fun newMsgGroup(param: NoticeReq): Observable<List<NoticeSummary>> {
        return apiService.newMsgGroup(param)
            .map(this::recordsConvert)
    }

    @Throws(NetException::class)
    private fun <T> recordsConvert(response: CommonDataResponse<RecordsResponse<T>>): List<T> {
        requireSuccess(response)
        return response.data!!.records
    }

    @Throws(NetException::class)
    private fun <T : CommonResponse> responseConvert(response: T): T {
        requireSuccess(response)
        return response
    }

    @Throws(NetException::class)
    private fun simpleConvert(response: CommonResponse): Boolean {
        requireSuccess(response)
        return true
    }

    @Throws(NetException::class)
    private fun <T> dataConvert(response: CommonDataResponse<T>): T {
        requireSuccess(response)
        return response.data!!
    }

    @Throws(NetException::class)
    private fun <T> listConvert(response: CommonRowsResponse<T>): List<T> {
        requireSuccess(response)
        return response.rows!!
    }

    @Throws(NetException::class)
    private fun requireSuccess(response: CommonResponse) {
        if (!response.isSuccess()) {
            throw NetException(response.code, response.message)
        }
    }

}