package com.sybotan.android.demo.viewmodel

import android.app.Application
import android.graphics.PointF
import android.text.TextUtils
import androidx.lifecycle.viewModelScope
import cn.hutool.core.util.IdUtil
import cn.sagacloud.android.cadengine.Lasso
import cn.sagacloud.android.cadengine.items.PipeLineItem
import cn.sagacloud.android.cadengine.items.PointItem
import cn.sagacloud.android.cadengine.items.TunableSpaceItem
import cn.sagacloud.android.cadengine.types.FloorData
import cn.sagacloud.android.cadengine.types.Photos
import cn.sagacloud.android.cadengine.types.Point
import cn.sagacloud.android.cadengine.types.PointZ
import com.framework.mvvm.model.db.entity.state
import com.framework.mvvm.model.db.entity.task.*
import com.framework.mvvm.model.repository.AdmRepository
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.sybotan.android.demo.activities.BaseActivity
import com.sybotan.android.demo.bean.result.*
import com.sybotan.android.demo.retrofit.BaseViewModelInterface
import com.sybotan.android.demo.tools.CommonUtils
import com.sybotan.android.demo.tools.ToastUtils
import com.sybotan.base.utils.SJsonUtil
import kotlinx.coroutines.launch
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.android.x.closestDI
import org.kodein.di.instance


/**
 * Created by lihao.
 * Date: 2021/6/9
 */
class SpaceMapVM(
    app: Application,
    b: BaseViewModelInterface?, activity: BaseActivity?, //建筑id
    private val buildingId: String, //楼层id
    private val floorId: String,
    private val projectId: String
) : BaseViewModel(app, b, activity), DIAware {
    private val gson = Gson()

    override val di: DI by closestDI()
    private val repo: AdmRepository by instance()

    /**
     * 查询空间和任务
     * archState 1:核查中;2:核查完毕
     * job：01-有结构核查任务 02-有结构问题 03-结构核查完毕 04-有现场勘测任务 05-已完成勘测任务
     */
    fun getSpaceJob() {
        viewModelScope.launch {
            val spaceList: ArrayList<JobSpaceEntity> = ArrayList()
            val spaceByArchState1 = repo.getSpaceByArchStateFloorId(floorId, "1")
            val spaceByArchState2 = repo.getSpaceByArchStateFloorId(floorId, "2")
            spaceList.addAll(spaceByArchState1)
            spaceList.addAll(spaceByArchState2)

            val spaceJobList = ArrayList<SpaceJobModel>()
            for (spaceEntity in spaceList) {
                val spaceJobModel = SpaceJobModel()
                val objectEntity = repo.getObject(spaceEntity.spaceId)
                spaceJobModel.buildingId = buildingId
                spaceJobModel.id = spaceEntity.spaceId
                spaceJobModel.localName = objectEntity!!.localName
                spaceJobModel.name = objectEntity.name
                spaceJobModel.projectId = projectId
                val infos = gson.fromJson(objectEntity.infos, InfosForObj::class.java)
                spaceJobModel.outline = infos.outline
                spaceJobModel.objectEntity = objectEntity
                val problems = repo.getProblemByAvalible(floorId)
                var hasProblem = false
                val list: ArrayList<PointF> = ArrayList()
                for (line in spaceJobModel.outline[0]!!) {
                    if (line.size < 1) {
                        list.add(PointF(line[0].x, line[0].y))
                        continue
                    }
                    for (p in line) {
                        list.add(PointF(p.x, p.y))
                    }
                }
                for (problem in problems) {
                    val geomList = gson.fromJson<List<PointF>>(
                        problem.geom,
                        object : TypeToken<List<PointF?>?>() {}.type
                    )
                    for (gemo in geomList) {
                        val pointF = if (geomList.size == 1) {
                            android.graphics.Point(
                                gemo.x.toInt(),
                                -gemo.y.toInt()
                            )
                        } else {
                            android.graphics.Point(
                                gemo.x.toInt(),
                                gemo.y.toInt()
                            )
                        }
                        if (Lasso.isPolygonContainsPoint(list, pointF)) {
                            hasProblem = true
                            break
                        }
                    }
                }
                if (spaceEntity.archState == 1) {
                    if (hasProblem) {
                        spaceJobModel.job = "02"
                    } else {
                        spaceJobModel.job = "01"
                    }
                } else {
                    spaceJobModel.job = "03"
                }
                spaceJobList.add(spaceJobModel)
            }
            mEmitter.SendDirective(SPACE_JOB, spaceJobList)

        }
    }

    /**
     * 添加空间核查问题
     *
     * @param x          x坐标
     * @param y          y坐标
     */
    fun addProblem(
        point: PointItem?,
        photos: ArrayList<Photos>,
        content: String,
        x: Float,
        y: Float,
        linePoints: ArrayList<PipeLineItem>,
        isLine: Boolean
    ) {
        viewModelScope.launch {
            //插入问题数据
            val array = ArrayList<PointF>()
            if (!isLine) {
                val position = PointF()
                position.x = x
                position.y = y
                if (point != null && point.data.mX != 0f) {
                    position.x = point.data.mX
                    position.y = point.data.mY
                }
                array.add(position)
            } else {
                val list = linePoints[linePoints.size - 1]
                for (p in list.data.points) {
                    val position = PointF()
                    position.x = p.x
                    position.y = p.y
                    array.add(position)
                }
            }
            val toJson = gson.toJsonTree(array)
            val toString = if (point != null && !TextUtils.isEmpty(point.data.id)) {
                point.data.id!!
            } else {
                IdUtil.simpleUUID()
            }

            val problem = ProblemArchEntity(
                id = toString,
                floorId = floorId,
                projectId = projectId,
                buildingId = buildingId,
                geomType = if (array.size == 1) "point" else "line",
                problemState = 1,
                message = content,
                valid = 1,
                state = 0,
                geom = toJson
            )
            repo.insProblem(problem)


            //插入文件数据
            for ((order, photo) in photos.withIndex()) {
                if (order != 0) {
                    val uuid = if (TextUtils.isEmpty(photo.id)) {
                        IdUtil.simpleUUID()
                    } else {
                        photo.id
                    }

                    val file = FileEntity(
                        id = uuid,
                        bizType = "problem_arch",
                        filePath = photo.key,
                        fileType = "photo",
                        clientPath = photo.path,
                        refObjId = toString,
                        orderNum = order,
                        projectId = projectId,
                        buildingId = buildingId,
                        floorId = floorId,
                        state = 0
                    )
                    repo.insFile(file)
                }
            }
            mEmitter.SendDirective(ADD_PROBLEM, null)
        }
    }

    /**
     * 查询空间核查问题
     *
     * @param choseSpace 选中的空间
     */
    fun getProblem(choseSpace: TunableSpaceItem?) {
        viewModelScope.launch {
            val problems = repo.getProblemByFloor(floorId)
            val models: ArrayList<ProblemsModel> = ArrayList()
            for (problem in problems) {
                if (problem.problemState == 1) {
                    val promodel = ProblemsModel()
                    promodel.content = problem.message
                    promodel.floorId = floorId
//                    promodel.spaceId = choseSpace!!.data.id
                    promodel.id = problem.id

                    val geomList = gson.fromJson<List<PointF>>(
                        problem.geom,
                        object : TypeToken<List<PointF?>?>() {}.type
                    )
                    promodel.geomType = problem.geomType
                    if (problem.geomType!! == "point") {
                        promodel.position = gson.toJson(geomList[0])
                    } else if (problem.geomType == "line") {
                        promodel.position = gson.toJson(geomList)
                    }
                    val refFiles = repo.getRefFile(problem.id)
                    for (file in refFiles) {
                        val photo = Photos()
                        photo.key = file.filePath
                        photo.id = file.id
                        photo.itemType = 0
                        photo.path = file.clientPath
                        promodel.photos.add(photo)
                    }
                    models.add(promodel)
                }
            }
            mEmitter.SendDirective(GET_PROBLEM, models)
        }
    }

    /**
     * 关闭空间核查问题
     *
     * @param point      点位
     */
    fun closeProblem(point: PointItem) {
        viewModelScope.launch {
            val problem = repo.getProblemById(point.data.id!!)
            problem.problemState = 2
            repo.insProblem(problem)
            mEmitter.SendDirective(CLOSE_PROBLEM, null)
        }
    }

    /**
     * 绑定二维码
     *
     * @param choseSpace 选中的空间
     * @param result     二维码uuid
     * @param point      点位信息
     * @param toString   z轴描述
     */
    fun bindQrcode(choseSpace: TunableSpaceItem?, result: String?, point: Point, toString: String) {
        viewModelScope.launch {
            val pointZ = PointZ()
            pointZ.x = point.mX
            pointZ.y = point.mY
            pointZ.z = toString.toFloat()
            val toJson = gson.toJsonTree(pointZ)
            val qrcode = QrCodeEntity(
                id = IdUtil.simpleUUID(),
                qrCode = result!!,
                objId = choseSpace!!.data.id!!,
                projectId = projectId,
                buildingId = buildingId,
                floorId = floorId,
                remark = "wall",
                state = 0,
                location = toJson
            )
            repo.insQrcode(qrcode)
            mEmitter.SendDirective(BIND_QECODE, null)
        }
    }

    /**
     * 查询对象绑定的二维码
     *
     * @param choseSpace 选中的空间
     */
    fun getQrcode(choseSpace: TunableSpaceItem?) {
        viewModelScope.launch {
            val qrcodes = repo.getQrcode(choseSpace!!.data.id!!)
            val qrcodeModels = ArrayList<QrcodeModel>()
            for (qrcode in qrcodes!!) {
                val qrcodeModel = QrcodeModel()
                qrcodeModel.obj_id = qrcode.objId
                qrcodeModel.qr_code = qrcode.qrCode
                val pointZ = gson.fromJson(qrcode.location, PointZ::class.java)
                val position = Position()
                position.x = pointZ.x.toString()
                position.y = pointZ.y.toString()
                position.z = Z()
                position.z.offset = pointZ.z.toString()
                position.z.region = "wall"
                qrcodeModel.position = gson.toJson(position)
                qrcodeModels.add(qrcodeModel)
            }
            mEmitter.SendDirective(GET_QECODE, qrcodeModels)
        }
    }

    /**
     * 设置空间的任务状态(新建和修改)
     *
     * @param choseSpace 选中的空间
     */
    fun setJob(choseSpace: TunableSpaceItem?, jobStatus: String) {
        viewModelScope.launch {
            if (jobStatus == "03") {
                val qrcodes = repo.getQrcode(choseSpace!!.data.id!!)
                if (CommonUtils.IsNull(qrcodes)) {
                    ToastUtils.showMyToast("未安装空间二维码，不能完成空间核查")
                    return@launch
                }
            }
            val space = repo.getSpaceBySpaceId(choseSpace!!.data.id!!)
            when (jobStatus) {
                "01" -> {
                    space.archState = 1
                }
                "03" -> {
                    space.archState = 2
                }
                "04" -> {
                    space.archState = 2
                    space.equipState = 1
                }
                "05" -> {
                    space.archState = 2
                    space.equipState = 2
                }
            }
            space.state()
            repo.insSpace(space)
            mEmitter.SendDirective(SET_JOB, null)
        }
    }


    fun getMap() {
        viewModelScope.launch {
            val floors = repo.getFloors()
            for (floor in floors) {
                if (floor.id == floorId) {
                    if (TextUtils.isEmpty(floor.floorMap)) {
                        ToastUtils.showMyToast("没有地图")
                        break
                    }
                    val floorOfflineData =
                        SJsonUtil.fromJson(floor.floorMap!!, FloorData::class.java)
                    mEmitter.SendDirective(MAP_LOAD, gson.toJson(floorOfflineData))
                    break
                }
            }

        }
    }

    fun insServeArea(deviceId: String, points: ArrayList<PointF>) {
        viewModelScope.launch {
            val geom = ArrayList<PointF>()
            geom.add(points[0])
            geom.add(PointF(points[0].x, points[1].y))
            geom.add(points[1])
            geom.add(PointF(points[1].x, points[0].y))
            var entity = repo.getServeAreaByObjId(deviceId)
            if (entity == null) {
                entity = ServeAreaEntity(
                    id = IdUtil.simpleUUID(),
                    projectId = projectId,
                    buildingId = buildingId,
                    floorId = floorId,
                    state = 0,
                    objId = deviceId,
                    geomType = "polygon",
                    geom = gson.toJsonTree(geom),
                )
            } else {
                entity.geom = gson.toJsonTree(geom)
                entity.state()
            }
            repo.insServeArea(entity)
            mActivity.finish()
        }
    }

    fun insServeAreas(deviceId: String, spaces: ArrayList<TunableSpaceItem>) {
        viewModelScope.launch {
            val geom = ArrayList<ArrayList<ArrayList<PointZ>>>()
            for (space in spaces) {
                geom.add(space.data.outLine!!)
            }
            var entity = repo.getServeAreaByObjId(deviceId)
            if (entity == null) {
                entity = ServeAreaEntity(
                    id = IdUtil.simpleUUID(),
                    projectId = projectId,
                    buildingId = buildingId,
                    floorId = floorId,
                    state = 0,
                    objId = deviceId,
                    geomType = "polygon",
                    geom = gson.toJsonTree(geom),
                )
            } else {
                entity.geom = gson.toJsonTree(geom)
                entity.state()
            }
            repo.insServeArea(entity)
            mActivity.finish()
        }
    }

    fun getServeArea(deviceId: String) {
        viewModelScope.launch {
            val entity = repo.getServeAreaByObjId(deviceId)
            if (entity != null) {
                val array = entity.geom!!.asJsonArray
                if (array[0].isJsonObject) {
                    val ar = gson.fromJson<List<PointF>>(
                        gson.toJson(entity.geom),
                        object : TypeToken<List<PointF?>?>() {}.type
                    )
                    mEmitter.SendDirective(SERVE_AREA, ar)
                } else {
                    val ar = gson.fromJson<List<ArrayList<ArrayList<PointZ>>>>(
                        gson.toJson(entity.geom),
                        object : TypeToken<List<ArrayList<ArrayList<PointZ>>>>() {}.type
                    )
                    mEmitter.SendDirective(SERVE_AREAS, ar)
                }
            }
        }
    }

    fun deleteServeArea(deviceId: String) {
        viewModelScope.launch {
            val entity = repo.getServeAreaByObjId(deviceId)
            if (entity != null) {
                entity.valid = 0
                entity.state()
                repo.insServeArea(entity)
            }
        }
    }


    companion object {
        const val MAP_LOAD = "MAP_LOAD"

        //查询空间和任务
        const val SPACE_JOB = "SPACE_JOB"

        //添加空间核查问题
        const val ADD_PROBLEM = "ADD_PROBLEM"

        //查询空间核查问题
        const val GET_PROBLEM = "GET_PROBLEM"

        //设置空间核查问题的信息和状态
        const val SET_PROBLEM = "SET_PROBLEM"

        //关闭空间核查问题
        const val CLOSE_PROBLEM = "CLOSE_PROBLEM"

        //绑定二维码
        const val BIND_QECODE = "BIND_QECODE"

        //查询对象绑定的二维码
        const val GET_QECODE = "GET_QECODE"

        //设置空间的任务状态(新建和修改)
        const val SET_JOB = "SET_JOB"
        const val PIPE = "PIPE"

        //服务区域
        const val SERVE_AREA = "SERVE_AREA"
        const val SERVE_AREAS = "SERVE_AREAS"

    }
}