package gaf3.core.services.user.service

import gaf3.core.data.PageParam
import gaf3.core.data.PagedData
import gaf3.core.exception.BusinessError
import gaf3.core.jpa.extension.findAll
import gaf3.core.services.user.dao.GafUserAccountDAO
import gaf3.core.services.user.dao.GafUserInfoDAO
import gaf3.core.services.user.domain.AcctForm
import gaf3.core.services.user.domain.CreateForm
import gaf3.core.services.user.domain.UpdateForm
import gaf3.core.services.user.domain.UserInfo
import gaf3.core.services.user.entity.GafUserAccount
import gaf3.core.services.user.entity.GafUserInfo
import gaf3.core.util.DataBeanHelper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.util.Assert
import org.springframework.validation.annotation.Validated
import java.util.*
import javax.transaction.Transactional
import kotlin.streams.toList

@Service
@Validated
class UserService(@Autowired private val userDao: GafUserInfoDAO, @Autowired private val acctDao: GafUserAccountDAO) {
//    companion object {
//        val log: Logger = LoggerFactory.getLogger(UserService::class.java)
//    }

    @Transactional
    fun create(data: CreateForm): UserInfo {
        // TODO: 验证信息
        Assert.hasText(data.name, "用户名不能为空")
        Assert.notNull(data.account, "账号信息不能为空")

        // TODO: 设置默认属性
        val userId = UUID.randomUUID().toString()
        var user = GafUserInfo()
        DataBeanHelper.Bean2Obj(data, user)
        user.userId = userId
        user.status = "0"

        // TODO: 保存数据
        user = userDao.save(user)
        createAcct(userId, data.account!!)
        return fetch(user.userId!!)!!
    }

    fun delete(userId: String) {
        // 验证信息
        Assert.hasText(userId, "用户ID不能为空")
        val entity: GafUserInfo = userDao.findById(userId).orElseThrow {
            throw BusinessError(BusinessError.ERR_DATA_NOTEXIST, "数据不存在")
        }
        if(entity.origin == "default") {
            throw BusinessError(BusinessError.ERR_SERVICE_FAULT, "默认用户不能删除")
        }
        // 删除数据
        acctDao.deleteById(userId)
        userDao.deleteById(userId)
    }

    fun update(userId: String, data: UpdateForm): UserInfo {
        // TODO: 验证信息
        Assert.hasText(userId, "用户ID不能为空")

        // TODO: 设置修改的属性
        val user = userDao.findByIdOrNull(userId) ?:
            throw BusinessError(BusinessError.ERR_DATA_NOTEXIST, "用户数据不存在")
        DataBeanHelper.Bean2Obj(data, user)

        userDao.save(user)
        return fetch(userId)!!
    }

    fun fetch(userId: String): UserInfo? {
        // TODO: 验证信息
        Assert.hasText(userId, "用户ID不能为空")

        val user = userDao.findByIdOrNull(userId) ?: return null
        val acct = acctDao.findByIdOrNull(userId)
        return convertDomain(user, acct)
    }

    fun fetchByAccount(account: String): UserInfo? {
        // TODO: 验证信息
        Assert.hasText(account, "用户ID不能为空")
        val acct = acctDao.findByAccount(account) ?: return null
        val user = userDao.findByIdOrNull(acct.userId) ?: return null
        return convertDomain(user, acct)
    }

    fun find(filter: UserInfo, paging: PageParam): PagedData<UserInfo> {
        val temp = GafUserInfo()
        DataBeanHelper.Bean2Obj(filter, temp)
        // val paged = userDao.findAll(example, PageRequest.of(page, limit, Sort.Direction.ASC, "createdAt"))
        val paged = userDao.findAll(temp, paging.sortBy("createdAt"))
        val rs = paged.content.parallelStream().map {
            p->convertDomain(p, acctDao.findByIdOrNull(p.userId))
        }.toList()

        return PagedData(rs, paged.totalElements.toInt())
    }

    fun changePass(userId: String, oldpass: String, newpass: String) {
        // TODO: 验证信息
        Assert.hasText(userId, "用户ID不能为空")
        Assert.hasText(oldpass, "oldpass不能为空")
        Assert.hasText(newpass, "newpass不能为空")

        // TODO: 设置修改的属性
        val acct = acctDao.findByIdOrNull(userId) ?:
            throw BusinessError(BusinessError.ERR_DATA_NOTEXIST, "用户数据不存在")
        if(acct.unwrapPass != oldpass){
            throw BusinessError(BusinessError.ERR_BAD_PASSWORD, "原有密码不正确")
        }
        acct.secret = newpass
        acctDao.save(acct)
    }

    fun createAcct(userId: String, data: AcctForm) {
        // TODO: 验证信息
        Assert.hasText(userId, "用户ID不能为空")
        Assert.hasText(data.account, "用户账号不能为空")
        Assert.hasText(data.secret, "用户口令不能为空")

        // TODO: 检查账号是否已存在
        if(acctDao.existsById(userId)) throw BusinessError(BusinessError.ERR_DATA_EXISTED, "用户账号已存在")
        if(acctDao.existsByAccount(data.account!!)) throw BusinessError(BusinessError.ERR_DATA_EXISTED, "账号已被占用")
        // TODO: 设置修改的属性
        val acct = GafUserAccount()
        acct.userId = userId
        acct.account = data.account
        acct.secret = data.secret
        acct.status = data.status ?: "0"
        acct.expired = data.expired ?: -1

        acctDao.save(acct)
    }

    fun updateAcct(userId: String, data: AcctForm) {
        // TODO: 验证信息
        Assert.hasText(userId, "用户ID不能为空")

        // TODO: 设置修改的属性
        val acct = acctDao.findByIdOrNull(userId) ?:
            throw BusinessError(BusinessError.ERR_DATA_NOTEXIST, "用户数据不存在")
        data.account = null
        DataBeanHelper.Bean2Obj(data, acct)
        acctDao.save(acct)
    }

    fun login(account: String, password: String): UserInfo {
        // TODO: 验证信息
        Assert.hasText(account, "账号不能为空")
        Assert.hasText(password, "密码不能为空")

        // TODO: 设置修改的属性
        val acct = acctDao.findByAccount(account) ?:
            throw BusinessError(BusinessError.ERR_USER_NOTEXIST, "用户数据不存在")
        if(acct.unwrapPass != password){
            throw BusinessError(BusinessError.ERR_BAD_PASSWORD, "用户密码不正确")
        }
        return fetch(acct.userId!!)?.apply {
            // 检查用户状态
            if(status != "0") {
                throw BusinessError(BusinessError.ERR_ACCESS_DENIED, "该用户禁止登录")
            }
        } ?: throw BusinessError(BusinessError.ERR_ACCESS_DENIED, "用户信息异常")
    }

    fun convertDomain(user: GafUserInfo, acct: GafUserAccount? = null): UserInfo {
        val data = UserInfo()
        DataBeanHelper.Bean2Obj(user, data)
        data.account = acct?.account
        data.expired = acct?.expired
        // data.status = acct?.status
        return data
    }
}