package cn.sagacloud.server.algorithm.services.endpoint

import cn.sagacloud.server.algorithm.dao.mapper.FloorMapper
import cn.sagacloud.server.algorithm.models.config.MyProperties
import cn.sagacloud.server.algorithm.models.modelFile.FloorModel
import cn.sagacloud.server.algorithm.models.modelFile.ModelFile
import cn.sagacloud.server.algorithm.models.request.DeleteFile
import cn.sagacloud.server.algorithm.models.request.MergeMultipartRequest
import cn.sagacloud.server.algorithm.models.request.UploadModelRequest
import cn.sagacloud.server.algorithm.services.BaseDataService
import cn.sagacloud.server.algorithm.services.CommonService
import cn.sagacloud.server.algorithm.services.http.HttpService
import com.alibaba.fastjson.JSON
import com.sybotan.database.SFilter
import com.sybotan.database.extensions.keyValue
import com.sybotan.service.SPageContext
import com.sybotan.service.models.enums.SResponseType
import com.sybotan.service.models.responses.SBaseResponse
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList

/**
 *
 *
 * @author jxing
 */
@Component
class ModelFileService {

    // 日志
    private val logger = LoggerFactory.getLogger(ModelFileService::class.java)

//    private var modelFileService = SObjectService(SMybatisDao(ModelFile::class.java))
//    private var modelFloorService = SObjectService(SMybatisDao(FloorModel::class.java))
    @Autowired
    lateinit var properties: MyProperties

    @Autowired
    lateinit var floorMapper: FloorMapper

    var dataService = BaseDataService

//    /**
//     * 删除模型文件
//     * 1. 只有一条记录的情况可以删除
//     * 2. 多条可以删除版本低于当前起作用版本的文件
//     * 3. 删除的模型文件记录加上删除标记
//     */
//    fun deleteModelFile(idList: ArrayList<ModelFile>):SBaseResponse{
//        val res = isDeletable(idList)
//        if(res != null)
//            return SBaseResponse(SResponseType.failure, res.id.toString())
//        idList.stream().forEach { file -> file.removed = true }
//        val update = SUpdateRequest<ModelFile>()
//        update.content = idList
//        update.projection = arrayListOf("removed")
//        modelFileService.updateList(update)
//        return SBaseResponse(SResponseType.success)
//    }
//
//    /**
//     * 检查是否全部符合删除规则
//     * return
//     *      null 全都符合
//     *      not null 发现的第一个不符合删除规则的模型文件
//     */
//    fun isDeletable (idList: ArrayList<ModelFile>): ModelFile?{
//        return null
//    }

    /**
     * 往url里上传file文件
     * @param url   url
     * @param file  文件
     * @return      是否上传成功
     */
    fun uploadFile(file: MultipartFile, url : String?): Boolean {
        if(file.isEmpty())
            return false
        //val uuid = CommonService.generateUUID("", true)
        val result = HttpService.sendFileByte(url, file.bytes)
        if(result.contains("success"))
            return true
        logger.error(result)
        return false
    }

    /**
     * 检查是否文件可以上传, 已废弃
     */
    fun checkUpdatable(file: MultipartFile, modelFile: ModelFile): Boolean {
        if(file.isEmpty || modelFile.floorModelId == null)
            throw Exception("文件为空或楼层id为空")
        val floors = dataService.floorModelService.select(SFilter.eq("id", modelFile.floorModelId!!)).exec()
        if(floors.isEmpty())
            throw Exception("指定楼层不存在")
        val floor = floors[0]
        if(floor.currentModelId == null)
            return true
        val files = dataService.modelFileService.select(SFilter.eq("id", floor.currentModelId!!)).exec()
        if(files.isEmpty())
            return true
        val single = files[0]
        if(single.status == null || 4 == single.status)
            return true
        return false
    }

    /**
     * 添加一条模型文件记录
     */
    fun addRecord(modelFile: ModelFile, properties: MyProperties?): Boolean {
        if(modelFile.id == null) {
            modelFile.id = CommonService.generateUUID("", true)
        }
        modelFile.upLoadUrl = CommonService.getFilePathInFileService(properties!!.fileService.uploadPath, modelFile.id!!)
        modelFile.url = CommonService.getFilePathInFileService(properties.fileService.downloadPath, modelFile.id!!)
        modelFile.status = 0
        modelFile.projectId = SPageContext.getHeader("ProjectId")
        var boolResult = dataService.modelFileService.replace(modelFile)
        if(!boolResult)
            return false
        val floors = dataService.floorModelService.select(SFilter.eq("id", modelFile.floorModelId!!)).exec()
        val floor = floors[0]
        floor.currentModelId = modelFile.id
        boolResult = dataService.floorModelService.update(floor, arrayListOf("currentModelId"))
        if(!boolResult)
            return false
        return true
    }

    /**
     * 将模型楼层的当前版本退回到上一个版本
     */
    fun backToLastVersion(modelFile: ModelFile) : Boolean{
        try {
            // 先删除本条模型记录
            val boolResult = dataService.modelFileService.delete(modelFile)
            if (!boolResult)
                logger.error("记录删除失败:${modelFile.id}")
            // 获取楼层
            val floors = dataService.floorModelService.select(SFilter.eq("id", modelFile.floorModelId!!)).exec()
            if (floors.isEmpty())
                return true
            val floor = floors[0]
            val modelFiles = dataService.modelFileService.select(SFilter.eq("floorModelId", modelFile.floorModelId!!)).exec()
            // 获取楼层最高版本
            val maxVersionId = getMaxVersionId(modelFiles)
            if(maxVersionId == null){
                // 删除楼层
                dataService.floorModelService.delete(floor)
                return true
            }
            // 修改当前模型id的为maxVersionId
            floor.currentModelId = maxVersionId
            dataService.floorModelService.update(floor, arrayListOf("currentModelId"))
            return true
        }catch (e : Exception){
            logger.error("模型文件退回上个版本出错: ${e.message}" )
            return false
        }
    }

    /**
     * 获取当前所有模型文件中版本号最大的模型id
     */
    private fun getMaxVersionId(modelFiles: ArrayList<ModelFile>): String? {
        if(modelFiles.isEmpty())
            return null
        var max : String? = null
        var version : Int = 0
        modelFiles.stream().forEach { model ->
            if(model.version!= null && model.version!! > version) {
                version = model.version!!
                    max = model.id
            }
        }
        return max
    }

    /**
     * 获取当前所有模型文件中创建时间最新的模型id
     */
    private fun getMaxCreateTimeId(modelFiles: ArrayList<ModelFile>): String? {
        if(modelFiles.isEmpty())
            return null
        var max : String? = null
        var createTime : Date? = null
        modelFiles.stream().forEach { model ->
            if(model.createTime!= null && createTime == null) {
                createTime = model.createTime!!
                max = model.id
            }else if(createTime != null && model.createTime != null && createTime!!.before(model.createTime)){
                createTime = model.createTime!!
                max = model.id
            }
        }
        return max
    }

    /**
     * 删除一个模型文件, 并在记录上做标记
     * 并将楼层的模型文件退回上个版本, 如果有的话
     */
    fun removeSingle(modelFile: ModelFile, properties: MyProperties, isForce: Boolean, isMarkDelete : Boolean): SBaseResponse {
        if(modelFile.id == null)
            return SBaseResponse(SResponseType.failure, "Id不能为null")
        val modelList = dataService.modelFileService.select(SFilter.eq("id", modelFile.id!!)).exec()
        if(modelList.isEmpty())
            return SBaseResponse(SResponseType.failure, "该模型文件不存在")
        val model = modelList[0]
        return removeAndGoBack(model, properties, isForce, isMarkDelete)
//        val floorList = modelFloorService.select(SFilter.Companion.eq("id", model.floorModelId!!)).exec()
//        if(floorList.isEmpty())
//            return SBaseResponse(SResponseType.failure, "该模型文件所属的文件夹不存在!")
//        val floor = floorList[0]

//        return SBaseResponse(SResponseType.failure, "")
    }

    /**
     * 将模型文件删除并将楼层的版本回退到上个版本
     * @param isForce 是否强制删除, 即跳过检查
     * @param isMarkDelete 是否是标记删除, false是真删除
     */
    fun removeAndGoBack(model: ModelFile, properties: MyProperties, isForce: Boolean, isMarkDelete : Boolean): SBaseResponse {
        if (model.floorModelId == null)
            return SBaseResponse(SResponseType.failure, "该模型文件已成孤儿文件")
        // 找出该楼层下是否只有一个模型文件
        val modelInFloorList = dataService.modelFileService.select(SFilter.eq("floorModelId", model.floorModelId!!), SFilter.eq("removed", false)).exec()

        if (modelInFloorList.isEmpty()) {
            return SBaseResponse(SResponseType.success, "")
        } else if (modelInFloorList.size == 1) { // 只有一个模型文件时删除记录和模型文件
            val result = removeFileFromFileServer(model) // ObjectMapper().writeValueAsString(deleteFile))
            if (result.contains("success")) {
                // 删除记录
                dataService.modelFileService.delete(model)
                deleteComponent(model.id!!)
                return SBaseResponse(SResponseType.success)
            } else {
                return SBaseResponse(SResponseType.failure, "文件服务器繁忙, 请稍后再试")
            }
        } else {
            // 多个模型文件时, 只能删除旧的模型文件(非当前)和标记删除;
            // 如果是版本最高的, 则不能删除, 如果是createTime最大的, 也不能删除
            // 获取楼层最高版本
            if(!isForce) {
                return SBaseResponse(SResponseType.failure, "该楼层有已有多个版本, 不能删除")
//                val maxVersionId = getMaxVersionId(modelInFloorList)
//                        ?: return SBaseResponse(SResponseType.failure, "模型正在处理中, 暂不能删除")
//                if (model.id.equals(maxVersionId)) {
//                    return SBaseResponse(SResponseType.failure, "该模型是最新模型, 不能删除!")
//                }
//                val maxCreateTimeId = getMaxCreateTimeId(modelInFloorList)
//                        ?: return SBaseResponse(SResponseType.failure, "模型正在处理中, 暂不能删除")
//                if (model.status != 11 && model.status != 21 && model.status != 0 && model.status != null && model.id.equals(maxCreateTimeId)) {
//                    return SBaseResponse(SResponseType.failure, "该模型正在处理中, 不能删除!")
//                }
            }
            // 删除模型文件
            return deleteAndGoBack(model, modelInFloorList)
        }
    }

    private fun deleteAndGoBack(model: ModelFile, modelInFloorList: ArrayList<ModelFile>): SBaseResponse {
        val result = removeFileFromFileServer(model)
        if (result.contains("success")) {
            // 标记删除
            removeFromList(modelInFloorList, model.id!!)
            model.removed = true
            model.url = null
            dataService.modelFileService.update(model)
            val floorModel = FloorModel()
            floorModel.id = model.floorModelId
            floorModel.currentModelId = getMaxVersionId(modelInFloorList)
            dataService.floorModelService.update(floorModel)
            // 删除所有该模型的构件信息
            deleteComponent(model.id!!)
            return SBaseResponse(SResponseType.success)
        } else {
            return SBaseResponse(SResponseType.failure, "文件服务器繁忙, 请稍后再试")
        }
    }

    private fun deleteComponent(modelId: String) {
        dataService.boundarySegmentService.delete(SFilter.eq("modelId", modelId))
        dataService.columnService.delete(SFilter.eq("modelId", modelId))
        dataService.componentService.delete(SFilter.eq("modelId", modelId))
        dataService.connectorService.delete(SFilter.eq("modelId", modelId))
        dataService.doorService.delete(SFilter.eq("modelId", modelId))
        dataService.ductService.delete(SFilter.eq("modelId", modelId))
        dataService.equipmentService.delete(SFilter.eq("modelId", modelId))
        dataService.gridService.delete(SFilter.eq("modelId", modelId))
        dataService.levelService.delete(SFilter.eq("modelId", modelId))
        dataService.otherService.delete(SFilter.eq("modelId", modelId))
        dataService.pipeService.delete(SFilter.eq("modelId", modelId))
        dataService.spaceService.delete(SFilter.eq("modelId", modelId))
        dataService.virtualWallService.delete(SFilter.eq("modelId", modelId))
        dataService.wallService.delete(SFilter.eq("modelId", modelId))
        dataService.windowService.delete(SFilter.eq("modelId", modelId))
    }

    /**
     * 在模型文件列表中, 删除指定id的模型文件
     */
    private fun removeFromList(modelInFloorList: ArrayList<ModelFile>, id: String) {
        var it = modelInFloorList.iterator()
        while (it.hasNext()){
            var item = it.next()
            if(item.id == id){
                it.remove()
                return
            }
        }
    }

    /**
     * 删除文件服务器中保存的模型文件
     */
    fun removeFileFromFileServer(model: ModelFile): String {
        val deleteFile = DeleteFile()
        deleteFile.keys!!.add(CommonService.getFilePathInFileService("${properties.fileService.dir}/", model.id!!))
        // 删除文件
        return HttpService.sendPost(properties.fileService.deletePath, JSON.toJSONString(deleteFile))
    }

    /**
     * 获取模型的上传用户id
     */
    fun getUserId(modelId: String): String?{
        val arr = dataService.modelFileService.select(SFilter.eq("id", modelId)).exec()
        if(arr.isNullOrEmpty())
            return null
        val model = arr[0]
        return model.userId
    }

    /**
     * 添加楼层
     */
    fun addFloor(request: UploadModelRequest): FloorModel {
        var floor = FloorModel()
        floor.id = CommonService.generateUUID("", true)
        floor.projectId = request.projectId
        floor.folderId = request.folderId
        floor.floorName = request.floorName
        if(!dataService.floorModelService.insert(floor))
            throw Exception("创建楼层失败")
        return floor
    }

    /**
     * 检查是否可以上传新模型
     */
    fun checkUpdatable(floor: FloorModel, request : UploadModelRequest) {
        if(floor.currentModelId == null)
            return
        val model = dataService.modelFileService.select(SFilter.eq("id", floor.currentModelId!!), SFilter.eq("removed", false)).entity()
        if(model == null)
            return
        if(model.status == 21 || model.status == 4)
            return
        // 如果正在上传中, 上传者本人又请求重新上传
        if(model.status == 0 && request.userId != null && request.userId.equals(model.userId)){
            val removeSingle = removeSingle(model, properties, true, true)
            if (removeSingle.result == SResponseType.success){
                return
            }else
                throw Exception("模型回滚异常, 请重试")
        }
        throw Exception("当前楼层有模型正在处理中, 请稍后再上传新模型")
    }

    fun addRecord(request: UploadModelRequest, floor: FloorModel, properties: MyProperties) : ModelFile{
        val model = ModelFile()
        model.id = CommonService.generateUUID("", true)
        model.projectId = request.projectId
        model.status = 0
        model.modelName = request.fileName
        model.floorModelId = floor.id
        model.note = request.note
        model.userId = request.userId
        model.userName = request.userName
        model.replaceReason = request.replaceReason
        model.size = request.size
        model.fileKey = "${model.id!!}.rvt"
        model.revitVersion = request.revitVersion
        model.url = CommonService.getFilePathInFileService(properties.fileService.downloadPath, model.id!!)
        if(!dataService.modelFileService.replace(model))
            throw Exception("添加模型失败")
        return model
    }

    fun updateCurrentModelId(floor: FloorModel, id: String) {
        var count = floorMapper.updateFloorCurrentModelId(floor.id!!, floor.currentModelId, id)
        if(count < 1)
            throw Exception("有其他人正在上传模型")
    }

    fun registerMultipartUpload(model: ModelFile, properties: MyProperties): String {
        val result = HttpService.sendPost(properties.fileService.registerMultipartUpload + model.fileKey, "")
        println(result+"11111111111111111111111111111111111111")
        val resultObj = JSON.parseObject(result)
        val uploadId = resultObj.getString("UploadId")
        if(uploadId.isNullOrEmpty())
            throw Exception("获取UploadId失败")
        return uploadId
    }

    val floorNamePattern = "^([F|B][1-9][0-9]{0,4}|RF)(M([1-9][0-9]{0,4})?)?\$"
    /**
     * 检查输入是否合法
     */
    fun checkUploadInputValid(request: UploadModelRequest) {
        if (request.projectId.isNullOrBlank() && SPageContext.getHeader("ProjectId").isNullOrBlank()) {
            throw Exception("projectId不能为空")
        }
        if(request.projectId.isNullOrBlank())
            request.projectId = SPageContext.getHeader("ProjectId")!!.trim()
        if(request.floorName.isNullOrBlank())
            throw Exception("楼层名不能为空")
        if(!Pattern.matches(floorNamePattern, request.floorName!!))
            throw Exception("楼层名格式不对")
        if(request.folderId.isNullOrBlank())
            throw Exception("文件夹未指定")
        if(request.fileName.isNullOrBlank() || request.fileName!!.length > 120){
            throw Exception("文件名不合法或太长")
        }
        if(request.userId.isNullOrBlank())
            throw Exception("用户id未指定")
    }

    fun checkMergeUploadInputValid(request: MergeMultipartRequest) {
        if(request.modelId.isNullOrBlank() || request.uploadId.isNullOrBlank() || request.md5.isNullOrBlank())
            throw Exception("输入参数错误")
    }

    fun mergeMultipart(uploadId: String, properties: MyProperties) : Boolean{
        val result = HttpService.sendPost(properties.fileService.mergeMultipartUpload + uploadId, "")
        return result.contains("success")
    }
}