package com.olegych.scastie.web.oauth2

import com.olegych.scastie.web.PlayJsonSupport

import akka.http.scaladsl._
import akka.http.scaladsl.model._
import HttpMethods.POST
import headers._
import Uri._
import unmarshalling.Unmarshal

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import com.olegych.scastie.api.User

import scala.concurrent.Future
import com.typesafe.config.ConfigFactory
import play.api.libs.json.{OFormat, Reads}

case class AccessToken(access_token: String)

class Github(implicit system: ActorSystem, materializer: ActorMaterializer) extends PlayJsonSupport {
  import system.dispatcher

  import play.api.libs.json._
  implicit val formatUser: OFormat[User] = Json.format[User]
  implicit val readAccessToken: Reads[AccessToken] = Json.reads[AccessToken]

  private val config =
    ConfigFactory.load().getConfig("com.olegych.scastie.web.oauth2")
  val clientId: String = config.getString("client-id")
  private val clientSecret = config.getString("client-secret")
  private val redirectUri = config.getString("uri") + "/callback"

  def getUserWithToken(token: String): Future[User] = info(token)
  def getUserWithOauth2(code: String): Future[User] = {
    def access = {
      Http()
        .singleRequest(
          HttpRequest(
            method = POST,
            uri = Uri("https://github.com/login/oauth/access_token").withQuery(
              Query(
                "client_id" -> clientId,
                "client_secret" -> clientSecret,
                "code" -> code,
                "redirect_uri" -> redirectUri
              )
            ),
            headers = List(Accept(MediaTypes.`application/json`))
          )
        )
        .flatMap(
          response => Unmarshal(response).to[AccessToken].map(_.access_token)
        )
    }

    access.flatMap(info)
  }

  private def info(token: String): Future[User] = {
    def fetchGithub(path: Path, query: Query = Query.Empty) = {
      HttpRequest(
        uri = Uri(s"https://api.github.com").withPath(path).withQuery(query),
        headers = List(Authorization(GenericHttpCredentials("token", token)))
      )
    }

    Http()
      .singleRequest(fetchGithub(Path.Empty / "user"))
      .flatMap(response => Unmarshal(response).to[User])
  }
}