package com.persagy.revit.services.monitor

import cn.sagacloud.server.algorithm.backstage.sync.SyncEquipPart
import cn.sagacloud.server.algorithm.backstage.sync.SyncObject
import com.persagy.database.SFilter
import com.persagy.revit.backstage.sync.SyncEquipment
import com.persagy.revit.backstage.sync.SyncFloor
import com.persagy.revit.backstage.sync.SyncISpace
import com.persagy.revit.backstage.sync.SyncModelComponent
import com.persagy.revit.models.config.MyProperties
import com.persagy.revit.models.jsonAnalyzer.AllComponents
import com.persagy.revit.models.jsonAnalyzer.BaseObj
import com.persagy.revit.models.modelFile.ModelFile
import com.persagy.revit.models.monitor.*
import com.persagy.revit.services.BaseDataService
import com.persagy.revit.services.CommonService
import com.persagy.revit.services.excel.ExcelService
import com.persagy.revit.services.http.HttpService
import com.persagy.revit.services.json.JSONAnalyzerService
import com.persagy.revit.services.modelCheck.ModelCheckService
import com.persagy.revit.services.modelCheck.ModelLogService
import com.persagy.service.models.enums.SResponseType
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.*
import kotlin.collections.ArrayList

@Service
class ModelMonitorService {

    val dataService = BaseDataService

    @Autowired
    lateinit var jsonAnalyzerService: JSONAnalyzerService

    @Autowired
    lateinit var modelCheckService: ModelCheckService

    @Autowired
    lateinit var myProperties: MyProperties

    @Autowired
    lateinit var modelLogService: ModelLogService

    /**
     * 获取后台监控信息by id
     */
    fun getModelMonitorById(modelId : String): ModelMonitor {
        var modelMonitor = dataService.modelMonitorService.select(SFilter.Companion.eq("id", modelId)).entity()
        if(modelMonitor == null)
        {
            modelMonitor = ModelMonitor()
            modelMonitor.id = modelId
            dataService.modelMonitorService.insert(modelMonitor)
        }
        return modelMonitor
    }

    /**
     * 开始上传模型
     */
    fun beginUpload(id: String) {
        val modelMonitor = getModelMonitorById(id)
        modelMonitor.uploadState = MntUploadState()
        modelMonitor.uploadState!!.beginTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("uploadState"))
    }

    /**
     * 结束上传模型
     */
    fun endUpload(modelId: String) {
        val modelMonitor = getModelMonitorById(modelId)
        if(modelMonitor.uploadState == null)
            modelMonitor.uploadState = MntUploadState()
        modelMonitor.uploadState!!.endTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("uploadState"))
    }

    /**
     * 调度器开始检查
     */
    fun beginCheck(id: String, date: Date) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.schedulerCheck!= null && modelMonitor.schedulerCheck!!.beginTime != null)
            return
        modelMonitor.schedulerCheck = MntSchedulerDispatch()
        modelMonitor.schedulerCheck!!.beginTime = date
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("schedulerCheck"))
    }

    /**
     * 调度器检查模型过程中, 设置下载模型文件完成时间
     */
    fun endSchedulerCheckDownload(modelId : String, date : Date?){
        if(date == null)
            return
        val modelMonitor = getModelMonitorById(modelId)
        if(modelMonitor.schedulerCheck == null){
            modelMonitor.schedulerCheck = MntSchedulerDispatch()
        }
        modelMonitor.schedulerCheck!!.downloadFinishTime = date
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("schedulerCheck"))
    }

    /**
     * 调度器导出模型数据过程中, 设置下载模型文件完成时间
     */
    fun endSchedulerExportDownload(modelId : String, date : Date?){
        if(date == null)
            return
        val modelMonitor = getModelMonitorById(modelId)
        if(modelMonitor.schedulerExport == null){
            modelMonitor.schedulerExport = MntSchedulerDispatch()
        }
        modelMonitor.schedulerExport!!.downloadFinishTime = date
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("schedulerExport"))
    }

    /**
     * 调度器结束检查
     */
    fun endCheck(id: String, date: Date) {
        val modelMonitor = getModelMonitorById(id)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.schedulerCheck == null) {
            modelMonitor.schedulerCheck = MntSchedulerDispatch()
            modelMonitor.schedulerCheck!!.beginTime = Date(date.time - (200 + Random().nextInt(100)) * 1000)
//            modelMonitor.schedulerCheck!!.beginTime = Date(System.currentTimeMillis() - (20 + Random().nextInt(100)) * 1000)
        }
        modelMonitor.schedulerCheck!!.endTime = date
        if (modelMonitor.schedulerCheck!!.downloadFinishTime == null){
            modelMonitor.schedulerCheck!!.downloadFinishTime = date
        }
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("schedulerCheck"))
    }

    /**
     * 模型检查
     */
    fun modelCheck(id: String, singleModelCheckBegin: Date, singleModelCheckEnd: Date) {
        val modelMonitor = getModelMonitorById(id)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.modelCheck == null) {
            modelMonitor.modelCheck = MntModelCheck()
        }
        modelMonitor.modelCheck!!.hasError = false
        modelMonitor.modelCheck!!.beginTime = singleModelCheckBegin
        modelMonitor.modelCheck!!.endTime = singleModelCheckEnd
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("modelCheck"))
    }

    /**
     * 模型检查 --出异常情况
     */
    fun modelCheck(id: String, errorMsg : String?, remove : Boolean) {
        val modelMonitor = getModelMonitorById(id)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.modelCheck == null) {
            modelMonitor.modelCheck = MntModelCheck()
        }
        modelMonitor.modelCheck!!.hasError = true
        modelMonitor.modelCheck!!.remove = remove
        modelMonitor.modelCheck!!.errorMsg = errorMsg
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("modelCheck"))
    }

    /**
     * 开始模型导出
     */
    fun beginExport(id: String, exportTime: Date) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.schedulerExport!= null && modelMonitor.schedulerExport!!.beginTime != null)
            return
        modelMonitor.schedulerExport = MntSchedulerDispatch()
        modelMonitor.schedulerExport!!.beginTime = exportTime
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("schedulerExport"))
    }

    /**
     * 模型导出 -- 异常情况
     */
    fun modelExport(id: String, errorMsg : String?, remove : Boolean) {
        val modelMonitor = getModelMonitorById(id)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.modelExport == null) {
            modelMonitor.modelExport = MntModelExport()
        }
        modelMonitor.modelExport!!.hasError = true
        modelMonitor.modelExport!!.remove = remove
        modelMonitor.modelExport!!.errorMsg = errorMsg
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("modelExport"))
    }

    /**
     * 模型导出 -- 正常情况
     */
    fun modelExport(id: String) {
        val modelMonitor = getModelMonitorById(id)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.modelExport == null) {
            modelMonitor.modelExport = MntModelExport()
        }
        modelMonitor.modelExport!!.hasError = false
        modelMonitor.modelExport!!.endTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("modelExport"))
    }

    /**
     * 监控导出jsonz文件到文件服务器
     * @param timeConsumed 上传jsonz消耗的时间,
     */
    fun exportJsonz(modelId: String, beginTime: Date, fileSize: Long) {
        val modelMonitor = getModelMonitorById(modelId)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.modelExport == null) {
            modelMonitor.modelExport = MntModelExport()
        }
        modelMonitor.modelExport!!.jsonzSize = fileSize
        modelMonitor.modelExport!!.jsonzBeginTime = beginTime
        modelMonitor.modelExport!!.jsonzEndTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("modelExport"))
    }

    /**
     * 正常结束导出模型
     */
    fun endExport(id: String, exportTime: Date) {
        val modelMonitor = getModelMonitorById(id)
        // 在某些情况可能会错过开始检查时间, 即补偿一个开始时间
        if(modelMonitor.schedulerExport == null) {
            modelMonitor.schedulerExport = MntSchedulerDispatch()
            modelMonitor.schedulerExport!!.beginTime = Date(exportTime.time - (200 + Random().nextInt(100)) * 1000)
//            modelMonitor.schedulerCheck!!.beginTime = Date(System.currentTimeMillis() - (20 + Random().nextInt(100)) * 1000)
        }
        modelMonitor.schedulerExport!!.endTime = exportTime
        if(modelMonitor.schedulerExport!!.downloadFinishTime == null){
            modelMonitor.schedulerExport!!.downloadFinishTime = exportTime
        }
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("schedulerExport"))
    }

    /**
     * 开始解析jsonz文件
     */
    private fun beginAnalyzeJsonz(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.jsonAnalysis!= null && modelMonitor.jsonAnalysis!!.beginTime != null)
            return
        modelMonitor.jsonAnalysis = MntModelAnalysis()
        modelMonitor.jsonAnalysis!!.beginTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("jsonAnalysis"))

    }

    /**
     * 监控jsonz解析
     */
    fun analyzeJsonz(id: String): BaseObj<AllComponents>? {
        beginAnalyzeJsonz(id)
        var jsonData : BaseObj<AllComponents>?
        var size = 0L
        try {
            val url = CommonService.getExportJSONDownloadUrl(id, myProperties)
//            size = CommonService.getRemoteHttpFileSize(url)
            val fileStream = HttpService.getInputStream(url)
            // 解析json
            jsonData = jsonAnalyzerService.analyzeJsonzFile(fileStream)
        }catch (e : Exception){
            endAnalyzeJsonzExceptionally(id, e.message + CommonService.getStackTrace(e))
            throw e
        }
        endAnalyzeJsonz(id, size)
        return jsonData
    }

    /**
     * 记录结束解析json时间
     */
    private fun endAnalyzeJsonz(id: String, size: Long) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.jsonAnalysis != null && modelMonitor.jsonAnalysis!!.endTime != null) {
            return
        }
        modelMonitor.jsonAnalysis!!.endTime = Date()
        modelMonitor.jsonAnalysis!!.hasError = false
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("jsonAnalysis"))
    }

    /**
     * 记录异常结束
     */
    private fun endAnalyzeJsonzExceptionally(id: String, errorInfo: String) {
        val modelMonitor = getModelMonitorById(id)
        modelMonitor.jsonAnalysis!!.hasError = true
        modelMonitor.jsonAnalysis!!.errorMsg = errorInfo
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("jsonAnalysis"))
    }

    /**
     * 持久化数据
     */
    fun persistenceData(id: String, objData: BaseObj<AllComponents>, bimIdPrefix : String) {
        beginPersistenceData(id)

        val importResult = jsonAnalyzerService.importModelData(objData, bimIdPrefix)
        if(importResult.result == SResponseType.failure){
            endPersistenceDataExceptionally(id, importResult.message)
            throw Exception(importResult.message)
        }
        endPersistenceData(id)
    }

    /**
     * 持久化数据异常
     */
    private fun endPersistenceDataExceptionally(id: String, errorInfo: String) {
        val modelMonitor = getModelMonitorById(id)
        modelMonitor.saveData!!.hasError = true
        modelMonitor.saveData!!.errorMsg = errorInfo
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("saveData"))
    }

    /**
     * 正常结束持久化
     */
    private fun endPersistenceData(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.saveData != null && modelMonitor.saveData!!.endTime != null) {
            return
        }
        modelMonitor.saveData!!.endTime = Date()
        modelMonitor.saveData!!.hasError = false
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("saveData"))
    }

    /**
     * 开始持久化数据
     */
    private fun beginPersistenceData(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.saveData!= null && modelMonitor.saveData!!.beginTime != null)
            return
        modelMonitor.saveData = MntSaveData()
        modelMonitor.saveData!!.beginTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("saveData"))
    }

    /**
     * 做多楼层检查
     */
    fun doMultiFloorCheck(model: ModelFile, excelService: ExcelService, projectId: String, folderId: String, floorName: String?): Boolean {
        beginMultiFloorCheck(model.id!!)
        val arrayList = ArrayList<Boolean>()
        var isPassed = false
        try {
            isPassed = modelCheckService.writeStatus3CheckReport(excelService, projectId, folderId, model, floorName, arrayList)
        }catch (e : Exception){
            endMultiFloorCheckExceptionally(model.id!!, "error:${e.message}, ${CommonService.getStackTrace(e)}")
            throw e
        }
        endMultiFloorCheck(model.id!!, arrayList)
        return isPassed
    }

    /**
     * 多楼层检查正常结束
     */
    private fun endMultiFloorCheck(id: String, results: ArrayList<Boolean>) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.multiFloorCheck != null && modelMonitor.multiFloorCheck!!.endTime != null) {
            return
        }
        modelMonitor.multiFloorCheck!!.levelCheck = results[0]
        modelMonitor.multiFloorCheck!!.gridCheck = results[1]
        modelMonitor.multiFloorCheck!!.endTime = Date()
        modelMonitor.multiFloorCheck!!.hasError = false
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("multiFloorCheck"))
    }

    /**
     * 多楼层检查异常结束
     */
    private fun endMultiFloorCheckExceptionally(id: String, errorInfo: String) {
        val modelMonitor = getModelMonitorById(id)
        modelMonitor.multiFloorCheck!!.hasError = true
        modelMonitor.multiFloorCheck!!.errorMsg = errorInfo
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("multiFloorCheck"))
    }

    /**
     * 多楼层检查开始
     */
    private fun beginMultiFloorCheck(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.multiFloorCheck!= null && modelMonitor.multiFloorCheck!!.beginTime != null)
            return
        modelMonitor.multiFloorCheck = MntMultiFloorCheck()
        modelMonitor.multiFloorCheck!!.beginTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("multiFloorCheck"))
    }

    /**
     * 同步数据到数据中心
     */
    fun syncDatacenter(modelId: String, syncFloor: SyncFloor, syncObjects: ArrayList<SyncObject>, bimIdPrefix: String) {
        beginSyncDatacenter(modelId)
        try {
            syncObjects.forEach {
                it.init(modelId, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
            }
//            syncEquip.init(id, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
//            syncEquipPart.init(id, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
//            syncISpace.init(id, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
//            syncModelComponent.init(id, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
        }catch (e : Exception){
            endSyncDatacenterExceptionally(modelId, "error:${e.message}, ${CommonService.getStackTrace(e)}")
            throw e
        }
        endSyncDatacenter(modelId)
    }

    /**
     * 同步数据到数据中心
     */
    fun syncDatacenter(modelId: String, syncEquip: SyncEquipment, syncEquipPart: SyncEquipPart, syncISpace: SyncISpace, syncFloor: SyncFloor, syncModelComponent : SyncModelComponent, bimIdPrefix: String) {
        beginSyncDatacenter(modelId)
        try {
            syncEquip.init(modelId, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
            syncEquipPart.init(modelId, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
            syncISpace.init(modelId, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
            syncModelComponent.init(modelId, syncFloor.floor!!, syncFloor.dcFloor, bimIdPrefix).prepareModelData().prepareDataCenterData().buildBIMIDMap().matchClassify().syncCreate().syncDelete().syncUpdate()
        }catch (e : Exception){
            endSyncDatacenterExceptionally(modelId, "error:${e.message}, ${CommonService.getStackTrace(e)}")
            throw e
        }
        endSyncDatacenter(modelId)
    }

    /**
     * 正常结束同步数据
     */
    private fun endSyncDatacenter(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.syncDatacenter != null && modelMonitor.syncDatacenter!!.endTime != null) {
            return
        }
        modelMonitor.syncDatacenter!!.endTime = Date()
        modelMonitor.syncDatacenter!!.hasError = false
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("syncDatacenter"))
    }

    /**
     * 异常结束同步数据
     */
    private fun endSyncDatacenterExceptionally(id: String, errorInfo: String) {
        val modelMonitor = getModelMonitorById(id)
        modelMonitor.syncDatacenter!!.hasError = true
        modelMonitor.syncDatacenter!!.errorMsg = errorInfo
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("syncDatacenter"))
    }

    /**
     * 记录开始同步数据到数据中心的时间
     */
    private fun beginSyncDatacenter(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.syncDatacenter!= null && modelMonitor.syncDatacenter!!.beginTime != null)
            return
        modelMonitor.syncDatacenter = MntSyncDatacenter()
        modelMonitor.syncDatacenter!!.beginTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("syncDatacenter"))
    }

    /**
     * 开始记录写日志
     */
    fun endWriteLog(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.saveLog != null && modelMonitor.saveLog!!.endTime != null) {
            return
        }
        modelMonitor.saveLog!!.endTime = Date()
        modelMonitor.saveLog!!.hasError = false
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("saveLog"))
    }

    /**
     * 异常结束写日志
     */
    fun endWriteLogExceptionally(id: String, errorInfo: String) {
        val modelMonitor = getModelMonitorById(id)
        modelMonitor.saveLog!!.hasError = true
        modelMonitor.saveLog!!.hasRetry = true
        modelMonitor.saveLog!!.errorMsg = errorInfo
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("saveLog"))
    }

    /**
     * 正常结束写日志
     */
    fun beginWriteLog(id: String) {
        val modelMonitor = getModelMonitorById(id)
        if(modelMonitor.saveLog!= null && modelMonitor.saveLog!!.beginTime != null)
            return
        modelMonitor.saveLog = MntSaveLog()
        modelMonitor.saveLog!!.beginTime = Date()
        dataService.modelMonitorService.update(modelMonitor, arrayListOf("saveLog"))
    }


}