package gitbucket.core.service

import gitbucket.core.model._
import org.scalatest.funsuite.AnyFunSuite
import gitbucket.core.model.Profile._
import gitbucket.core.model.Profile.profile.blockingApi._

class AccessTokenServiceSpec extends AnyFunSuite with ServiceSpecBase {

  test("generateAccessToken") {
    withTestDB { implicit session =>
      assert(AccessTokenService.generateAccessToken("root", "note") match {
        case (id, token) => id != 0
      })
    }
  }

  test("getAccessTokens") {
    withTestDB { implicit session =>
      val (id, token) = AccessTokenService.generateAccessToken("root", "note")
      val tokenHash = AccessTokenService.tokenToHash(token)

      assert(AccessTokenService.getAccessTokens("root") == List(AccessToken(`id`, "root", `tokenHash`, "note")))
    }
  }

  test("getAccessTokens(root) get root's tokens") {
    withTestDB { implicit session =>
      val (id, token) = AccessTokenService.generateAccessToken("root", "note")
      val tokenHash = AccessTokenService.tokenToHash(token)
      val user2 = generateNewAccount("user2")
      AccessTokenService.generateAccessToken("user2", "note2")

      assert(AccessTokenService.getAccessTokens("root") == List(AccessToken(`id`, "root", `tokenHash`, "note")))
    }
  }

  test("deleteAccessToken") {
    withTestDB { implicit session =>
      val (id, token) = AccessTokenService.generateAccessToken("root", "note")
      val user2 = generateNewAccount("user2")
      AccessTokenService.generateAccessToken("user2", "note2")

      AccessTokenService.deleteAccessToken("root", id)

      assert(AccessTokenService.getAccessTokens("root").isEmpty)
    }
  }

  test("getAccountByAccessToken") {
    withTestDB { implicit session =>
      val (id, token) = AccessTokenService.generateAccessToken("root", "note")
      assert(AccessTokenService.getAccountByAccessToken(token) match {
        case Some(user) => user.userName == "root"
        case _          => fail()
      })
    }
  }

  test("getAccountByAccessToken don't get removed account") {
    withTestDB { implicit session =>
      val user2 = generateNewAccount("user2")
      val (id, token) = AccessTokenService.generateAccessToken("user2", "note")
      AccountService.updateAccount(user2.copy(isRemoved = true))

      assert(AccessTokenService.getAccountByAccessToken(token).isEmpty)
    }
  }

  test("generateAccessToken create uniq token") {
    withTestDB { implicit session =>
      val tokenIt = List("token1", "token1", "token1", "token2").iterator
      val service = new AccessTokenService {
        override def makeAccessTokenString: String = tokenIt.next()
      }

      assert(service.generateAccessToken("root", "note1")._2 == "token1")
      assert(service.generateAccessToken("root", "note2")._2 == "token2")
    }
  }

  test("when update Account.userName then AccessToken.userName changed") {
    withTestDB { implicit session =>
      val user2 = generateNewAccount("user2")
      val (id, token) = AccessTokenService.generateAccessToken("user2", "note")

      Accounts.filter(_.userName === "user2".bind).map(_.userName).update("user3")

      assert(AccessTokenService.getAccountByAccessToken(token) match {
        case Some(user) => user.userName == "user3"
        case _          => fail()
      })
    }
  }
}
