package http.client

import http.client.factory.RetrofitFactory
import http.exception.NetException
import http.vo.request.*
import http.vo.response.*
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import xn.xxp.room.bean.LabConfig
import xn.xxp.room.bean.NoticeSummary
import java.io.File
import java.lang.StringBuilder

object ApiRepository {

    private val mLibClient by lazy {
        RetrofitFactory().createLabClient()
    }

    /**
     * 登录获取token
     */
//    fun authOneLogin(param: AccessTokenReq): Observable<Boolean> {
//        return mLibClient.authOneLogin(param).schedulers()
//    }

    /**
     * 查询APK版本
     *
     * @param param 设备版本信息
     */
    fun apkVersion(param: ApkInfoReq): Observable<ApkInfoResp> {
        return mLibClient.apkVersion(param).schedulers()
    }

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

    /**
     * 危险源信息
     *
     * @param param 实验室Id、分页信息
     */
    fun hazardlist(param: HazardReq): Observable<List<LabHazardVo>> {
        return mLibClient.hazardlist(param).schedulers()
    }

    /**
     * 签到验证（进入）
     *
     * @param eBoard 是否为电子信息牌
     * @param subId 实验室id
     * @param username 学生卡编号/人员id
     */
    fun signInCheck(eBoard: Boolean, subId: String, username: String): Observable<SignInCheckResp> {
        return mLibClient.signInCheck(eBoard, subId, username).schedulers()
    }

    /**
     * 签到提交-人脸验证
     */
    fun signInFace(code: String, faceFeature: SignInReq? = null): Observable<String> {
        return mLibClient.signInFace(code, faceFeature).schedulers()
    }

    /**
     * 签到-安全准入检测三合一
     *
     * @param patrolSign 是否为巡查签到
     */
    fun checkInAll(patrolSign: Boolean, param: CheckInAllReq): Observable<Boolean> {
        return mLibClient.checkInAll(patrolSign, param).schedulers()
    }

    /**
     * 签到提交
     */
    fun signIn(id: String): Observable<Boolean> {
        return mLibClient.signIn(id).schedulers()
    }

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

    /**
     * 签到提交
     * @param jumpSafetyCheck 是否跳过安全检查
     * @param code 查询人员状态返回的code
     * @param id 人脸比对成功后返回的id
     */
    fun signIn(jumpSafetyCheck: Boolean, code: String, id: String): Observable<Boolean> {
        return if (jumpSafetyCheck) {
            signInJump(id, code)
        } else {
            signIn(id)
        }
    }

    /**
     * 签到验证（离开）
     *
     * @param eBoard 是否为电子信息牌
     * @param subId 实验室id
     * @param username 学生卡编号/人员id
     */
    fun signOutCheck(
        eBoard: Boolean,
        subId: String,
        username: String
    ): Observable<SignInCheckResp> {
        return mLibClient.signOutCheck(eBoard, subId, username).schedulers()
    }

    /**
     * 离开提交
     */
    fun signOut(code: String): Observable<Boolean> {
        return mLibClient.signOut(code).schedulers()
    }

    /**
     * 获取实验室一体机可控制设备
     *
     * @param subId 实验室id
     */
    fun controllerList(subId: String): Observable<List<LotDeviceVo>> {
        return mLibClient.controllerList(subId).schedulers()
    }

    /**
     * 控制设备
     *
     * @param param 设备编号、命令
     */
    fun sendControllerCMD(param: ControllerCMD): Observable<Boolean> {
        return mLibClient.sendControllerCMD(param).schedulers()
    }

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

    /**
     * 实验室预警测点
     *
     * @param subId 实验室id
     */
    fun warnList(subId: String): Observable<List<LabWarnVo>> {
        return mLibClient.warnList(subId).schedulers()
    }

    /**
     * 人脸比对
     */
    fun faceCompare(param: FaceCompareReq): Observable<Boolean> {
        return mLibClient.faceCompare(param).schedulers()
    }

    /**
     * 心跳
     *
     * @param num 设备唯一编码
     */
    fun heartbeat(num: String): Observable<Boolean> {
        return mLibClient.heartbeat(num).schedulers()
    }

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

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

    /**
     * 一体机查询危化品
     */
    fun hazardBookList(): Observable<List<HazardBook>> {
        return mLibClient.hazardBookList().schedulers()
    }

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


    /**
     * 实验室文化图
     */
    fun bannerImages(param: BannerImageReq): Observable<List<BannerImageBean>> {
        return mLibClient.bannerImages(param).schedulers()
    }

    /**
     * 文字转语音
     */
    fun textParseVideo(text: String): Observable<SpeakInfo> {
        return mLibClient.textParseVideo(text).schedulers()
    }

    /**
     * 物联控制权限验证
     */
    fun lotInCheck(subId: String, username: String): Observable<String> {
        return mLibClient.lotInCheck(subId, username).schedulers()
    }

    /**
     * 查询实验室配置
     */
    fun queryLabConfig(deviceNum: String): Observable<LabConfig> {
        return mLibClient.queryLabConfig(deviceNum).schedulers()
    }

    fun laboratoryInfo(openEBoard: Boolean, id: String): Observable<LaboratoryVo> {
        return if (openEBoard) laboratoryInfoEBoard(id) else laboratoryInfo(id)
    }

    fun laboratoryInfoEBoard(labId: String): Observable<LaboratoryVo> {
        val observable1 = mLibClient.homeTopInfo(labId)
        val observable2 = mLibClient.homeMiddleInfo(labId)

        return Observable.zip(observable1, observable2, { top, middle ->
            LaboratoryVo().apply {
                subId = labId
                rectangleLogo = top.circularLogo
                subName = top.subjectName

                dangerColor = middle.filedColor
                dangerName = middle.typeName
                dangerLevel = middle.levelName
                address = middle.subjectName
                deptName = middle.deptName
                qrCodeUrl = middle.qrCodeUrl
                adminName = middle.adminName
                adminPhone = middle.adminPhone
                adminUserDesc = "${middle.adminName ?: ""}  |  ${middle.adminPhone ?: ""}"
                safeUserDesc = middle.safeUserVoList?.fold("") { acc, safeUserVo ->
                    "$acc  ${safeUserVo.safeUserName ?: ""}  |  ${safeUserVo.safeUserPhone ?: ""}"
                }
                buildName = middle.buildName
                room = middle.room
                // 责任单位、实验室负责人
                val safePersons = mutableListOf(
                    LaboratoryVo.SafePersonInfo("责任单位：", middle.deptName),
                    LaboratoryVo.SafePersonInfo(
                        "实验室负责人：",
                        middle.adminName,
                        middle.adminPhone
                    ),
                )
                // 安全责任人
                safePersonList = middle.safeUserVoList?.mapTo(safePersons) { item ->
                    LaboratoryVo.SafePersonInfo(
                        "安全责任人：",
                        item.safeUserName,
                        item.safeUserPhone
                    )
                } ?: safePersons
                val specialList = middle.brandInfoSubjectVos?.filter { it.isSpecial == "1" }
                specialClassify = specialList?.flatMap { it.classifyList }?.let { list ->
                    mutableListOf<String>().apply {
                        for (i in list.indices step 3) {
                            val builder = StringBuilder()
                            builder.append(list[i])
                            if (i + 1 < list.size) builder.append("    ").append(list[i + 1])
                            if (i + 2 < list.size) builder.append("    ").append(list[i + 2])
                            add(builder.toString())
                        }
                    }
                }
                specialClassify2 = specialList?.map { it.classifyList }
                safeClassifyList = middle.brandInfoSubjectVos?.filter { it.isSpecial != "1" }
                inCheck = middle.inCheck
                inspectInCheck = middle.inspectInCheck
                outCheck = middle.outCheck
            }
        }).schedulers()
    }

    /**
     * 查询首页右侧人员信息
     */
    fun homeRightInfo(labId: String): Observable<HomeRightResp> {
        return mLibClient.homeRightInfo(labId).schedulers()
    }

    /**
     * 实验室介绍
     */
    fun labIntro(labId: String): Observable<String> {
        return mLibClient.labIntro(labId).schedulers()
    }

    /**
     * 查询值班人员列表
     */
    fun dutyUserList(labId: String, startTime: String): Observable<DutyPersonVo> {
        return mLibClient.dutyUserList(labId, startTime).schedulers()
    }

    /**
     * 查询实验人员列表
     */
    fun signUserList(labId: String): Observable<List<LabPersonVo>> {
        return mLibClient.signUserList(labId).schedulers()
    }

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

    /**
     * 查询巡查人员列表
     */
    fun inspectUserList(labId: String, startTime: String): Observable<DutyPersonVo> {
        return mLibClient.inspectUserList(labId, startTime).schedulers()
    }

    /**
     * 查询值班人员/巡查人员
     * @param type 1-值班人员 2-巡查人员
     */
    fun queryDutyPerson(type: Int, labId: String, startTime: String): Observable<DutyPersonVo> {
        return if (1 == type) dutyUserList(labId, startTime) else inspectUserList(labId, startTime)
    }

    /**
     * 查询实验人员/准入人员
     * @param type 1-实验人员 2-准入人员
     */
    fun queryAccessPerson(
        type: Int,
        labId: String,
        pageNumber: Int,
        pageSize: Int
    ): Observable<List<LabPersonVo>> {
        return if (1 == type) signUserList(labId) else securityUserList(labId, pageNumber, pageSize)
    }

    /**
     * 视频监控
     */
    fun cameraBySubjectId(
        labId: String,
        userId: String,
        username: String,
        source: Int
    ): Observable<List<MonitorVo>> {
        return mLibClient.cameraBySubjectId(labId, userId, username, source).schedulers()
    }

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

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

    /**
     * 指纹录入
     */
    fun addUserFinger(param: UserFingerVo): Observable<Boolean> {
        return mLibClient.addUserFinger(param).schedulers()
    }

    /**
     * 删除指纹
     */
    fun deleteFingerById(id: String): Observable<Boolean> {
        return mLibClient.deleteFingerById(id).schedulers()
    }

    /**
     * 获取人像特征值
     */
    fun faceFeature(file: File): Observable<String> {
        return mLibClient.faceFeature(file).schedulers()
    }

    /**
     * 人脸识别
     */
    fun authFace(file: File, labId: String): Observable<UserVo> {
        return mLibClient.faceFeature(file)
            .flatMap {
                val faceAuthReq =
                    AuthFaceReq(it, labId)
                mLibClient.multiFaceDetection(faceAuthReq)
            }.schedulers()
    }

    /**
     * 刷卡验证
     */
    fun authCard(labId: String, cardNum: String): Observable<UserVo> {
        return mLibClient.cardValidate(labId, cardNum).schedulers()
    }

    /**
     * 密码验证
     */
    fun authPassword(param: AuthPwdReq): Observable<UserVo> {
        return mLibClient.pwdValidate(param).schedulers()
    }

    /**
     * 签到人像比对
     */
    fun signFaceMatching(file: File, code: String): Observable<String> {
        return mLibClient.faceFeature(file)
            .flatMap { feature ->
                val param = SignInReq()
                param.data = feature.toByteArray()
                mLibClient.signInFace(code, param)
            }.schedulers()
    }

    /**
     * 离开人像比对
     */
    fun leaveFaceMatching(file: File, userId: String): Observable<Boolean> {
        return mLibClient.faceFeature(file)
            .flatMap { feature ->
                val param = FaceCompareReq()
                param.data = feature.toByteArray()
                param.userId = userId
                mLibClient.faceCompare(param)
            }.schedulers()
    }

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

    /**
     * 巡查签到
     */
    fun signInWithPatrol(param: PatrolSignInReq): Observable<Boolean> {
        return mLibClient.signInWithPatrol(param).schedulers()
    }

    /**
     * 巡查签退
     */
    fun signOutWithPatrol(param: PatrolSignOutReq): Observable<Boolean> {
        return mLibClient.signOutWithPatrol(param.labId, param.userId).schedulers()
    }

    /**
     * 巡查签退/准入签退判断
     *  true-巡查 false-准入
     */
    fun isSignInType(labId: String, userId: String): Observable<Boolean> {
        return mLibClient.isSignInType(labId, userId).schedulers()
    }

    /**
     * 准入签到：跳过人脸，传空数据即可
     *
     * @param code 查询人员状态返回的code
     *
     */
    fun jumpFaceSignIn(code: String): Observable<Boolean> {
        return mLibClient.signInFace(code, SignInReq())
            .flatMap { id ->
                mLibClient.signInJump(id, code)
            }.schedulers()
    }

    /**
     * 信息牌准入签到，前置检测
     */
    fun accessSignCheck(param: CommonSignInReq): Observable<SignFaceVo> {
        return mLibClient.signInCheck(true, param.labId, param.userId)
            .flatMap { response ->
                if (!response.state) {
                    val message =
                        if (response.message.isNullOrEmpty()) "核验失败，请联系管理员！" else response.message[0]
                    throw NetException("500", message)
                }
                mLibClient.signInFace(response.code, SignInReq())
                    .map { SignFaceVo(it, response.code) }
            }.schedulers()
    }

    /**
     * 巡查签到、准入签到(无AI检查) 通用接口
     *
     * 一、巡查签到
     *   #signInCheckWithPatrol labId userId
     *   #signInWithPatrol num userId
     *
     * 二、准入签到(无AI检查)
     *   #signInCheck(true, labId, userId)
     *   #jumpFaceSignIn(code)
     *
     * @param signType 1-准入签到 2-巡查签到
     */
    fun commonSignIn(signType: Int, param: CommonSignInReq): Observable<Boolean> {
        return if (2 == signType) {
            mLibClient.signInCheckWithPatrol(param.labId, param.userId)
                .flatMap {
                    val reqParam = PatrolSignInReq().apply {
                        num = param.num
                        userId = param.userId
                        subjectId = param.labId
                    }
                    mLibClient.signInWithPatrol(reqParam)
                }.schedulers()
        } else {
            mLibClient.signInCheck(true, param.labId, param.userId)
                .flatMap { response ->
                    if (!response.state) {
                        val message =
                            if (response.message.isNullOrEmpty()) "核验失败，请联系管理员！" else response.message[0]
                        throw NetException("500", message)
                    }
                    mLibClient.signInFace(response.code, SignInReq())
                        .map { SignFaceVo(it, response.code) }
                }.flatMap { face ->
                    mLibClient.signInJump(face.id, face.code)
                }.schedulers()
        }
    }

    /**
     * 巡查签退、准入签退(无离开检查项) 通用接口
     *
     * 一、巡查签退
     *   #signOutWithPatrol labId userId
     *
     * 二、准入签退(无离开检查项)
     *   #signOutCheck(true, labId, userId)
     *   #signOut(code)
     *
     * @param signType 1-准入签到 2-巡查签到
     */
    fun commonLeave(signType: Int, labId: String, userId: String): Observable<Boolean> {
        return if (2 == signType) {
            mLibClient.signOutWithPatrol(labId, userId).schedulers()
        } else {
            mLibClient.signOutCheck(true, labId, userId)
                .flatMap { response ->
                    if (!response.state) {
                        val message =
                            if (response.message.isNullOrEmpty()) "核验失败，请联系管理员！" else response.message[0]
                        throw NetException("500", message)
                    }
                    mLibClient.signOut(response.code)
                }.schedulers()
        }
    }

    /**
     * 巡查签到，前置检测
     */
    fun patrolSignCheck(param: CommonSignInReq): Observable<Boolean> {
        return mLibClient.signInCheckWithPatrol(param.labId, param.userId).schedulers()
    }

    /**
     * 滚动消息列表
     */
    fun newMsgGroup(param: NoticeReq): Observable<List<NoticeSummary>> {
        return mLibClient.newMsgGroup(param).schedulers()
    }


}

fun <T : Any> Observable<T>.schedulers(): Observable<T> {
    return this.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
}