package com.cclotus.register.service

import cclotus.weixin.api.service.WxAppLoginService
import com.cclotus.register.GafAuthConfigure
import com.cclotus.register.domain.WXUser
import com.cclotus.register.enum.UserType
import com.cclotus.register.mapper.WXUserMapper
import com.cclotus.register.vo.LoginResult
import com.cclotus.register.vo.LoginUserInfo
import com.ruoyi.common.exception.ServiceException
import com.ruoyi.common.utils.uuid.UUID
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import org.springframework.beans.BeanUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.Instant
import java.util.*

/**
 * 微信登录服务
 */
@Service
class WXLoginService(val config: GafAuthConfigure) {

    @Autowired(required = false)
    lateinit var wxAppLoginService: WxAppLoginService

    @Autowired
    lateinit var userService: WXUserService

    @Autowired
    lateinit var wxUserMapper: WXUserMapper

    /**
     * 用户登录
     *
     * @return 当前登录的用户信息
     */
    @Transactional
    fun login(jsCode: String, appId: String): LoginResult {
        var role: String = UserType.USER.role
        // 获取openId
        val jsCode2Session = wxAppLoginService.code2Session(appId, jsCode)
        val openId = jsCode2Session.openid ?: throw ServiceException("获取用户openId失败")
        var user = userService.findUserByOpenID(openId)
        if (user == null) {
            // 如果根据openId未查找到此用户，证明为新用户，创建临时token信息
            user = WXUser()
            user.userId = UUID.fastUUID().toString()
            user.openid = openId
            user.name = "游客"
            // 该用户为游客身份
            role = UserType.GUEST.role
        }
        val loginUserInfo = LoginUserInfo().apply {
            BeanUtils.copyProperties(user, this)
        }
        return LoginResult().apply {
            this.user = loginUserInfo
            this.role = role
            this.token = createJwt(loginUserInfo, role)
        }
    }

    /**
     * 注册用户信息
     * @param user 微信用户信息
     * @return 新登录信息
     */
    fun register(user: WXUser): LoginResult {
        val loginUserInfo = user.apply {
            this.userId = this.userId ?: UUID.fastUUID().toString()
        }.let {
            // 根据openid查询指定用户信息是否存在
            userService.findUserByOpenID(user.openid!!, null)?.run {
                if (this.deleted == 0) throw ServiceException("用户已注册")
                it.userId = this.userId
                it.deleted = 0
                // 注销后重复注册不改变推荐人信息
                if (!this.referrer.isNullOrBlank()) it.referrer = this.referrer
            }
            // 查询手机号码是否被注册
            if (userService.checkPhoneExistence(it.phone!!)) throw ServiceException("该手机号已注册")
            userService.saveOrUpdate(it)
            LoginUserInfo().apply {
                BeanUtils.copyProperties(it, this)
            }
        }
        // 构造登录信息
        return LoginResult().apply {
            this.token = createJwt(loginUserInfo, UserType.USER.role)
            this.user = loginUserInfo
            this.role = UserType.USER.role
        }
    }

    /**
     * 用户注销
     *
     * @param userId
     */
    fun unregister(userId: String): Int {
        return userService.deleteUserById(userId)
    }

    /**
     * 根据登录用户生成认证token
     *
     * @param user 当前登录用户
     * @param role 当前登录用户角色
     * @return 认证token
     */
    fun createJwt(user: LoginUserInfo, role: String): String {
        val builder = Jwts.builder()
            .setSubject(user.openid)
            .setIssuer(config.jwtIssuer ?: "gaf")
            .setExpiration(Date.from(Instant.now().plusSeconds(config.jwtValiditySec)))
            .claim("userId", user.userId)
            .claim("name", user.name)
            .claim("role", role)
            .claim("phone", user.phone)
        val secretKeyBytes = config.jwtSecret?.toByteArray()?.copyOf(32)
        val alg: SignatureAlgorithm = SignatureAlgorithm.HS256
        return builder.signWith(alg, secretKeyBytes).compact()
    }
}
