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

import cn.sagacloud.server.algorithm.common.utils.FloorLevelCheckUtil
import cn.sagacloud.server.algorithm.common.utils.GridGroupUtil
import cn.sagacloud.server.algorithm.models.dataCheck.GridCheckResult
import cn.sagacloud.server.algorithm.models.dataCheck.LevelCheckResult
import cn.sagacloud.server.algorithm.models.entities.Grid
import cn.sagacloud.server.algorithm.models.excel.IsPassedEnum
import cn.sagacloud.server.algorithm.models.excel.report.ModelGridReport
import cn.sagacloud.server.algorithm.models.excel.report.ModelLevelReport
import cn.sagacloud.server.algorithm.models.excel.report.BlockingTotalReport
import cn.sagacloud.server.algorithm.models.modelFile.FloorModelView
import cn.sagacloud.server.algorithm.models.modelFile.ModelFile
import cn.sagacloud.server.algorithm.models.scheduler.SagaCheckResult
import cn.sagacloud.server.algorithm.models.scheduler.UnitCheckResult
import cn.sagacloud.server.algorithm.services.comparator.FloorComparator
import cn.sagacloud.server.algorithm.services.endpoint.FloorModelService
import cn.sagacloud.server.algorithm.services.excel.ExcelService
import cn.sagacloud.server.algorithm.services.message.MessageService
import com.sybotan.database.SFilter
import com.sybotan.mybatis.SMybatisDao
import com.sybotan.service.SBaseService
import com.sybotan.service.SObjectService
import com.sybotan.service.SPageContext
import com.sybotan.service.models.requests.SQueryRequest
import com.sybotan.service.utils.SSpringContextUtil
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import java.lang.StringBuilder
import java.util.stream.Collectors
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletRequestWrapper
import kotlin.collections.Map as Map

@Component
class ModelCheckService {

    @Autowired
    lateinit var messageService: MessageService

    @Autowired
    lateinit var floorComparator: FloorComparator
    /**
     * 检查轴网
     */
    fun checkGrid(projectId : String, folderId : String, modelId : String): ArrayList<GridCheckResult> {
//        var gridCheckService = SBaseService(SMybatisDao(GridCheckResult::class.java))
//        var queryBuilder = gridCheckService.selectAll()
//        queryBuilder.tableName = "revit_calc.check_grid_valid('${projectId}', '${folderId}', '${modelId}')"
        // 查询楼层模型
        var request = SQueryRequest()
        request.filters = " projectId = '"+projectId+"' and folderId = '"+ folderId!! +"' and ( status = 4 or currentModelId = '" + modelId!! + "') ";
        val select = FloorModelService.pageQuery(request)
        var list = select.content
        if(list == null || list.isEmpty()){
            return ArrayList()
        }
        // 收集modelId
        val idSet = HashSet<String>();
        for(model in list) {
            idSet.add(model.currentModelId!!)
        }
        // 查询Grid
        var gridService = SObjectService(SMybatisDao(Grid::class.java))
        val gridRs = gridService.pageQuery(SQueryRequest(), arrayListOf(SFilter.inList("modelId", arrayListOf(idSet))))
        val grids = gridRs.content;
        val gridMap = grids!!.groupBy { it.id }
        // 获取分组
        return GridGroupUtil.checkGridUpright(list, gridMap) as ArrayList<GridCheckResult>
    }

    /**
     * 检查标高
     */
    fun checkLevel(projectId : String, folderId : String, modelId : String): ArrayList<LevelCheckResult> {
//        var levelCheckService = SBaseService(SMybatisDao(LevelCheckResult::class.java))
//        var queryBuilder = levelCheckService.selectAll()
//        queryBuilder.tableName = "revit_calc.check_level_valid('${projectId}', '${folderId}', '${modelId}')"
//        return queryBuilder.exec()
        // 查询楼层模型
        var request = SQueryRequest()
        request.filters = " projectId = '"+projectId+"' and folderId = '"+ folderId!! +"' and ( status = 4 or currentModelId = '" + modelId!! + "') ";
        val select = FloorModelService.pageQuery(request)
        var list = select.content
        if(list == null || list.isEmpty()){
            return ArrayList()
        }
        // 检查标高
        return FloorLevelCheckUtil.checkLevel(list) as ArrayList<LevelCheckResult>
    }

    /**
     * 写检查轴网, 检查标高的报告
     * @return 检查结果是否出错, false表示失败, true表示检查都正常
     */
    fun writeStatus3CheckReport(excelService: ExcelService, projectId: String, folderId: String, model: ModelFile, floorName: String?, results : ArrayList<Boolean>) : Boolean{
        val levelCheckResult = checkLevel(projectId, folderId, model.id!!)
        levelCheckResult.sortWith(floorComparator)
        val gridCheckResult = checkGrid(projectId, folderId, model.id!!)
        gridCheckResult.sortWith(floorComparator)
        val involvedFloor = HashSet<String>()
        /** 标高 */
        val isLevelError = writeLevelReport(levelCheckResult, excelService, involvedFloor)
        val isGridError = writeGridReport(gridCheckResult, excelService, model.id!!)
        results.add(isLevelError)
        results.add(isGridError)
        if(!isLevelError && !isGridError){
            return true
        }
        writeTotalReport(excelService, isLevelError, isGridError, floorName, involvedFloor)
        //保存excel报告到文件服务器
        excelService.saveToFileServer(model.id!!)
        return false
    }

    /**
     * 写阻塞性总体报告excel
     */
    private fun writeTotalReport(excelService: ExcelService, levelError: Boolean, gridError: Boolean, floorName: String?, involvedFloor: HashSet<String>) {
        var totalReport = SSpringContextUtil.getBean(BlockingTotalReport::class.java) as BlockingTotalReport
//        totalReport.writeToRow(SagaCheckResult.sheetCheckName, IsPassedEnum.getIsPassedEnum(true))
        totalReport.writeToRow(SagaCheckResult.sheetCheckName, IsPassedEnum.Pass)
        totalReport.writeToRow(UnitCheckResult.sheetCheckName, IsPassedEnum.Pass)
        if(levelError)
            totalReport.writeToRow("楼层标高与楼层顺序号检查", IsPassedEnum.Unpass)
        else
            totalReport.writeToRow("楼层标高与楼层顺序号检查", IsPassedEnum.Pass)
        if(gridError)
            totalReport.writeToRow("轴网检查", IsPassedEnum.Unpass)
        else
            totalReport.writeToRow("轴网检查", IsPassedEnum.Pass)
        totalReport.addCellValue(0, 1, floorName?:"")
        val sb = StringBuilder()
        for (singleFloorName in involvedFloor){
            sb.append(singleFloorName).append(", ")
        }
        if(sb.length > 1)
            sb.removeSuffix(", ")
        totalReport.addCellValue(2, 1, sb.toString())
        excelService.insertReport(totalReport)
        excelService.randomWrite(0, totalReport.cellValues)
    }

    /**
     * 写标高报告, 返回是否有错误
     */
    private fun writeLevelReport(levelCheckResult: ArrayList<LevelCheckResult>, excelService: ExcelService, involvedFloor : HashSet<String>): Boolean{
        var levelReport = SSpringContextUtil.getBean(ModelLevelReport::class.java) as ModelLevelReport
        var hasError = false
        for(levelCheck in levelCheckResult){
            var row = ModelLevelReport.Data()
            row.floorName = levelCheck.floorName?: ""
            if(row.floorName.isNotEmpty() && !involvedFloor.contains(row.floorName)){
                involvedFloor.add(row.floorName)
            }
            row.planName = levelCheck.planName?: ""
            row.levelHeight = (levelCheck.elevation?.div(1000))?.toString()?:""
            if(levelCheck.hasError == false)
                row.isPassed = IsPassedEnum.Pass
            else
                row.isPassed = IsPassedEnum.Unpass
            row.note = levelCheck.errorMsg?:""
            if(levelCheck.hasError == true)
                hasError = true
            levelReport.rowValue.add(row)
        }
        excelService.insertReport(levelReport)
        return hasError
    }

    /**
     * 写轴网报告, 返回是否有错误
     */
    fun writeGridReport(gridCheckResult: ArrayList<GridCheckResult>, excelService: ExcelService, modelId: String): Boolean{
        var gridReport = SSpringContextUtil.getBean(ModelGridReport::class.java) as ModelGridReport
        var hasError = hasMultiGroups(gridCheckResult)
        for(gridCheck in gridCheckResult){
            var row = ModelGridReport.Data()
            row.floorName = gridCheck.floorName?: ""
            row.gridGroup = gridCheck.groupId?.toString()?:""
            if(gridCheck.currentModelId == modelId && hasError) {
                row.isPassed = IsPassedEnum.Unpass
                row.note = "轴网不一致"
            }else{
                row.isPassed = IsPassedEnum.Pass
                row.note = ""
            }
            gridReport.rowValue.add(row)
        }
        excelService.insertReport(gridReport)
        return hasError
    }

    /**
     * 检查轴网是否有多个分组
     */
    private fun hasMultiGroups(gridCheckResult: ArrayList<GridCheckResult>) : Boolean{
        val groupSet = HashSet<Int>()
        for(gridCheck in gridCheckResult) {
            if(gridCheck.groupId != null && !groupSet.contains(gridCheck.groupId!!)){
                if(groupSet.size != 0){
                    return true
                }
                groupSet.add(gridCheck.groupId!!)
            }
        }
        return false
    }
}