package cn.sagacloud.server.algorithm.services.modelCheck

import cn.sagacloud.server.algorithm.backstage.model.CreateRequest
import cn.sagacloud.server.algorithm.backstage.model.QueryRequest
import cn.sagacloud.server.algorithm.backstage.request.task.TaskCmd
import cn.sagacloud.server.algorithm.models.dataCheck.*
import cn.sagacloud.server.algorithm.models.entities.Project
import cn.sagacloud.server.algorithm.models.modelFile.*
import cn.sagacloud.server.algorithm.services.endpoint.ReportService
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import com.alibaba.fastjson.TypeReference
import com.sybotan.database.SFilter
import com.sybotan.mybatis.SMybatisDao
import com.sybotan.service.SObjectService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.concurrent.CompletableFuture


/**
 *
 *
 * @author jxing
 */
@Suppress("UNCHECKED_CAST")
@Service
class TaskService {

    // var taskRequest = TaskRequest()
    @Autowired
    private lateinit var taskRequest: TaskRequest

    @Autowired
    private lateinit var reportService: ReportService

    val projectService = SObjectService(SMybatisDao(Project::class.java))  // 项目

    /**
     * 查询任务
     */
    fun queryTask(modelFileList: ArrayList<ModelFile>, cmd : TaskCmd) : ArrayList<TaskEntity>?{
        val request = QueryRequest()
        val sb = StringBuilder()
        sb.append("Id in [\"")
        modelFileList.forEach {
            if(it.taskInfo == null)
                return@forEach
            when(cmd){
                TaskCmd.DataCheck ->
                    if(it.taskInfo!!.checkTask != null){
                        val task = it.taskInfo!!.checkTask
                        if (task!!.id != null) {
                            sb.append(task.id)
                            sb.append("\",\"")
                        }
                    }
                TaskCmd.DataExport ->
                    if(it.taskInfo!!.exportTask != null){
                        val task = it.taskInfo!!.exportTask
                        if (task!!.id != null) {
                            sb.append(task.id)
                            sb.append("\",\"")
                        }
                    }
            }
        }
        if(sb.endsWith(",\"")) {
            sb.deleteCharAt(sb.length - 1)
            sb.deleteCharAt(sb.length - 1)
        }
        sb.append("]")
        request.filters = sb.toString()
        val response = taskRequest.queryTask(request)
        if(response.result == "success"){
            return response.content
        }else
            return null
    }

    /**
     * 查询DataCheck任务结果
     */
    fun queryTaskResult(taskId : String) : String? {
        val request = QueryRequest()
        val sb = StringBuilder()
        sb.append("TaskId in [\"${taskId}\"]")
        request.filters = sb.toString()
        val response = taskRequest.queryTaskResult(request)
        if(response.result == "success"){
            try {
                return response.content?.get(0)!!.content
            }catch (e : Exception){
                return ""
            }
        }else
            return null
    }

    /**
     * 添加Task, 包含下载文件
     */
    fun addTask(modelFileList: ArrayList<ModelFile>, cmd : TaskCmd) : Boolean{
        val taskIdMap = addTasks(modelFileList, cmd)
        if(taskIdMap.isEmpty())
            return false
        return addDownload(taskIdMap, modelFileList)
    }

    /**
     * 给已添加的任务添加下载文件
     */
    private fun addDownload(taskIdMap: Map<String, String>, modelFileList: ArrayList<ModelFile>): Boolean {
        val request = CreateRequest<DownloadEntity>()
        modelFileList.forEach { modelFile ->
            if(taskIdMap.containsKey(modelFile.id)) {
                val download = DownloadEntity()
                download.httpUrl = modelFile.url
                download.md5 = modelFile.md5
                download.taskId = taskIdMap[modelFile.id!!]
                if (request.content == null)
                    request.content = ArrayList()
                request.content!!.add(download)
            }
        }
        val response = taskRequest.createDownload(request)
        return response.result == "success"
    }

    /**
     * 在revit调度器端添加任务
     */
    private fun addTasks(modelFileList: ArrayList<ModelFile>, cmd : TaskCmd) : Map<String, String>{
        val request = CreateRequest<TaskEntity>()
        var pconfig: Project?
        modelFileList.forEach { modelFile ->
            val task = TaskEntity()
            task.cmd = cmd.name
            task.expectedFinishTime = 24 * 60 * 60
            task.modelId = modelFile.id
            task.name = modelFile.modelName
            task.param = ""
            task.projectId = modelFile.projectId
            pconfig = projectService.select(SFilter.eq("id",modelFile.projectId!!)).entity()
            if(pconfig != null){
                val configJSON = pconfig!!.configJson!!
                task.floorServerUrl = configJSON.floorServerUrl
                task.useablePhaseName = configJSON.useablePhaseName
                task.sagaSign = configJSON.sagaSign
                task.checkItems = configJSON.checkItems
                task.facilityParameters = configJSON.facilityParameters
                task.spaceParameters = configJSON.spaceParameters
                task.roomParameters = configJSON.roomParameters
                task.mEPCurveParameters = configJSON.mEPCurveParameters
                task.equipComponentCode = configJSON.equipComponentCode
            }
            if(request.content == null)
                request.content = ArrayList()
            request.content!!.add(task)
        }
        val response = taskRequest.createTask(request)
        val map = HashMap<String, String>()  // modelId --> 调度器taskId
        val resultMap = HashMap<String, TaskEntity>()
        if(response!!.entityList != null && response.entityList!!.isNotEmpty()){
            response.entityList!!.forEach { taskEntity ->
                if(taskEntity.modelId != null && taskEntity.id != null) {
                    map[taskEntity.modelId!!] = taskEntity.id!!
                    resultMap[taskEntity.modelId!!] = taskEntity
                }
            }
            modelFileList.forEach { modelFile ->
                if(modelFile.taskInfo == null)
                    modelFile.taskInfo = SchedulerInfo()
                if(resultMap.containsKey(modelFile.id)) {
                    when (cmd) {
                        TaskCmd.DataCheck -> modelFile.taskInfo!!.checkTask = resultMap[modelFile.id]
                        TaskCmd.DataExport -> modelFile.taskInfo!!.exportTask = resultMap[modelFile.id]
                    }
                }
            }
        }
        return map
    }

    /**
     * 获取多个模型的DataCheck结果
     */
    fun getAllDataCheckResult(arr : ArrayList<FloorModelView>) : HashMap<String, RevitDataCheckResult>{
        val resultMap = HashMap<String, RevitDataCheckResult>()
        try {
            val futures: Array<CompletableFuture<*>?> = arrayOfNulls<CompletableFuture<*>>(arr.size)
            for (i in arr.indices) {
                val taskId = arr[i].taskInfo!!.checkTask!!.id
                futures[i] = CompletableFuture.supplyAsync<String?> { queryTaskResult(taskId!!) }
            }
            CompletableFuture.allOf(*futures).join()
            for (i in arr.indices) {
                val floorName = arr[i].floorName
                val result = futures[i]!!.get() as String?
                if (result.isNullOrEmpty()) {
                    continue
                }
                val checkData = JSON.parseObject(result)
                resultMap.put(floorName!!, getRevitDataCheckResult(checkData))
            }
        }catch (e : Exception){
        }
        return resultMap
    }

    fun hasAllDataCheckResultError(checkData: JSONObject) : Boolean {
        val revitDataCheckResult = getRevitDataCheckResult(checkData)
        if (reportService.countError(revitDataCheckResult.elementRangeCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.familyNameCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.columnCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.connectorCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.systemNameCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.equipInSpaceCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.pipeCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.systemReferEquipCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.parameterIntegrityCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.xyzOverlapCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        if(reportService.countError(revitDataCheckResult.equipPartLocationCheck as ArrayList<DataCheckResultBase?>?) > 0)
            return false
        return true
    }

    /**
     * 处理模型的DataCheck结果为实体类
     */
    private fun getRevitDataCheckResult(checkData: JSONObject): RevitDataCheckResult {
        val content = checkData.get("Content") as JSONArray
        val checkResult = RevitDataCheckResult()
        for (subItem in content){
            val item = subItem as JSONObject
            when(item.getString("Name").toLowerCase()){
                "ElementRangeCheck".toLowerCase() ->{
                    val elementRangeCheckArr: ArrayList<ElementRangeCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<ElementRangeCheck?>?>() {})
                    checkResult.elementRangeCheck = elementRangeCheckArr
                }
                "FamilyNameCheck".toLowerCase() ->{
                    val familyNameCheckArr: ArrayList<FamilyNameCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<FamilyNameCheck?>?>() {})
                    checkResult.familyNameCheck = familyNameCheckArr
                }
                "EquipPartLocationCheck".toLowerCase() ->{
                    val equipPartLocationCheckArr: ArrayList<EquipPartLocationCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<EquipPartLocationCheck?>?>() {})
                    checkResult.equipPartLocationCheck = equipPartLocationCheckArr
                }
                "ColumnCheck".toLowerCase() ->{
                    val columnCheckArr: ArrayList<ColumnCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<ColumnCheck?>?>() {})
                    checkResult.columnCheck = columnCheckArr
                }
                "ConnectorCheck".toLowerCase() ->{
                    val connectorCheckArr: ArrayList<ConnectorCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<ConnectorCheck?>?>() {})
                    checkResult.connectorCheck = connectorCheckArr
                }
                "SystemNameCheck".toLowerCase() ->{
                    val systemNameCheckArr: ArrayList<SystemNameCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<SystemNameCheck?>?>() {})
                    checkResult.systemNameCheck = systemNameCheckArr
                }
                "EquipInSpaceCheck".toLowerCase() ->{
                    val equipInSpaceCheckArr: ArrayList<EquipInSpaceCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<EquipInSpaceCheck?>?>() {})
                    checkResult.equipInSpaceCheck = equipInSpaceCheckArr
                }
                "PipeCheck".toLowerCase() ->{
                    val pipeCheckArr: ArrayList<PipeCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<PipeCheck?>?>() {})
                    checkResult.pipeCheck = pipeCheckArr
                }
                "SystemReferEquipCheck".toLowerCase() ->{
                    val systemReferEquipCheckArr: ArrayList<SystemReferEquipCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<SystemReferEquipCheck?>?>() {})
                    checkResult.systemReferEquipCheck = systemReferEquipCheckArr
                }
                "ParameterIntegrityCheck".toLowerCase() ->{
                    val parameterIntegrityCheckArr: ArrayList<ParameterIntegrityCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<ParameterIntegrityCheck?>?>() {})
                    checkResult.parameterIntegrityCheck = parameterIntegrityCheckArr
                }
                "XYZOverlapCheck".toLowerCase() ->{
                    val xyzOverlapCheckArr: ArrayList<XYZOverlapCheck?>? = JSON.parseObject(item.getJSONArray("Content").toString(), object : TypeReference<ArrayList<XYZOverlapCheck?>?>() {})
                    checkResult.xyzOverlapCheck = xyzOverlapCheckArr
                }
            }
        }
        return checkResult
    }
}