package gaf3.core.services.bind.service

import gaf3.core.data.PagedData
import gaf3.core.exception.BusinessError
import gaf3.core.services.bind.dao.GafBindItemDAO
import gaf3.core.services.bind.domain.BatchBindForm
import gaf3.core.services.bind.domain.BatchBindResult
import gaf3.core.services.bind.domain.BindForm
import gaf3.core.services.bind.entity.GafBindItem
import gaf3.core.util.DataBeanHelper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Example
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.stereotype.Service
import org.springframework.util.Assert.*
import java.util.*
import javax.transaction.Transactional

@Service("gafBindService")
class BindService(@Autowired val itemDao: GafBindItemDAO) {
    fun create(type: String, form: BindForm): GafBindItem {
        // TODO: 检查数据约束
        hasText(type, "type不能为空")
        hasText(form.source, "source不能为空")
        hasText(form.target, "target不能为空")
        if(itemDao.exists(type, form.source, form.target)) throw BusinessError(BusinessError.ERR_DATA_EXISTED, "绑定关系已经存在")

        // TODO: 保存数据
        var entity = GafBindItem()
        DataBeanHelper.Bean2Obj(form, entity)
        entity.id = UUID.randomUUID().toString()
        entity.type = type
        entity = itemDao.save(entity)
        return entity
    }

    @Transactional
    fun batchCreate(type: String, replace: Boolean, form: BatchBindForm): BatchBindResult {
        // 参数检查
        hasText(type, "type不能为空")
        hasText(form.source, "source不能为空")
        notEmpty(form.targets, "targets不能为空")
        form.targets?.all { p -> !p.isBlank() }?.let { isTrue(it, "targets不能包含空项") }
        val (source,targets) = form
        val binds = mutableListOf<GafBindItem>()
        val skips = mutableListOf<GafBindItem>()
        val result = mutableListOf<GafBindItem>()
        binds.addAll(itemDao.findByTypeAndSource(type, source))

        // 循环保存数据
        // 检查绑定数据，确保业务逻辑正确，绑定数据相关appId和userId存入作冗余字段
        targets?.forEach { target ->
            val skipped = binds.removeIf { p -> p.target == target && skips.add(p)}
            if(!skipped) {
                var entity = GafBindItem()
                DataBeanHelper.Bean2Obj(form, entity)
                entity.id = UUID.randomUUID().toString()
                entity.type = type
                entity.target = target
                entity = itemDao.save(entity)
                result.add(entity)
            }
        }
        // 删除多余数据
        if(replace) {
            binds.forEach { p->itemDao.delete(p) }
        }

        return BatchBindResult(result, skipped = skips, deleted = if(replace) binds else null)
    }

    fun delete(id: String) {
        if(!itemDao.existsById(id)) throw BusinessError(BusinessError.ERR_DATA_NOTEXIST)
        itemDao.deleteById(id)
    }

    @Transactional
    fun delete(type: String, source: String? = null, target: String? = null) {
        itemDao.delete(type, source, target)
    }

    fun find(type: String, source: String?, target: String?): PagedData<GafBindItem> {
        val filter = GafBindItem()
        filter.type = type
        filter.source = source
        filter.target = target
        val example = Example.of(filter)
        val rs = itemDao.findAll(example, PageRequest.of(0, 500, Sort.Direction.ASC, "createdAt"))
        return PagedData(rs.content, rs.totalElements.toInt())
    }
}