/*
 * Copyright (C) 2020  Prasoon Joshi
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import play.api.Configuration
import play.api.libs.ws.ahc.AhcWSClient
import play.libs.ws.ahc.WSClientComponents
import play.api.libs.concurrent.AkkaComponents
import play.api.libs.ws.WSResponse
import scala.xml.NodeSeq
import scala.concurrent.ExecutionContext
import scala.util.Try
import com.lucidchart.open.xtract.XmlReader
import scala.util.Success
import scala.util.Failure
import play.api.libs.ws.WSClient
import javax.inject._

import models._
import graphql.SchemaInputObjects._

import com.softwaremill.macwire._
import graphql.SchemaInputObjects._
import scala.concurrent.Future
import play.components.ConfigurationComponents
import play.api.libs.json.JsValue

package object repository {

  trait DatabaseServer {

  }

  trait HttpServiceComponent {
    val httpService: HttpService

    class HttpService @Inject() (ws: WSClient) {
      def getFromUrl[A](url: String) = {
        ws.url(url).get()
      }
    }
  }

  trait Repository {

  }

//  import ExecutionContext.Implicits.global
  trait DataRepository extends Repository {

    //TODO: Related to the mycelium aspect of niosx
    def fromRemote(blob: String): Seq[MilliEntity]

    def allFindingAid: List[models.MilliEntity]
    def findingAid(id: String): Option[models.MilliEntity]

    def csvIngest(csvIngestInput: CsvIngestInput): Int
    def saveRdfDocument(scheme: String, line: String): Option[Int]
    def rdfIngest(scheme: String, line: String): Int

    def addEntity(entityInput: MilliEntityInput): Future[Option[models.MilliEntity]]
    def addAnnotation(annotation: AnnotationInput): Future[Option[models.Annotation]]
    def addComment(comment: CommentInput): Future[Option[models.Annotation]]
    def addSubject(sub: SubjectIn): Future[Option[Subject]]
    def addSubjectAnno(in: SubjectAnnoInput): Future[Option[Annotation]]

    def findEntity(id: String): Option[MilliEntity]
    def nonPaginatedSearch(blob: String): Seq[MilliEntity]
    def paginatedSearch(next: Long,
      afterCursor: Option[String],
      filters: EntityFilterInput): Page
    def isValidGraphId(graphId: String): Boolean
    
    def find[E <: NiosxEntity](id: String): Option[E]
    def textSearch[E <: NiosxEntity](blob: String): Seq[E]
  }

  trait UserRepository extends Repository {
    def addUser(user: UserInput): String 
    def editUser(user: UserInput): Option[NiosxUser]
    /**
     * Authenticate the passed username and password and return
     * a token that identifies the user session.
     */
    def authenticate(username: String, password: String): Option[AuthPayload]
    def authorise(token: String): Option[NiosxUser]
    def findUserByUsername(username: String): Option[NiosxUser]
  }

  trait RepositoryComponent {

    val dataRepository: DataRepository
    val userRepository: UserRepository
//    val databaseServer: DatabaseServer
  }

  import play.api.libs.ws.ahc.AhcWSComponents
  import repository.GremlinServer
  import repository.SimpleUserRepository
  import play.api.libs.concurrent.CustomExecutionContext
  import scala.concurrent.ExecutionContext
  import akka.actor.ActorSystem
  
  trait NiosxExecutionContext extends ExecutionContext

  class NiosxExecutionCtxImpl(system: ActorSystem)
    extends CustomExecutionContext(system, "contexts.repository-dispatcher")
    with NiosxExecutionContext

  trait RepositoryModule extends AhcWSComponents {
    
    def ec: NiosxExecutionContext// = wire[NiosxExecutionCtxImpl]
    lazy val gremlinServer = wire[GremlinServer]
    lazy val dataRepository = wire[MockDataRepository]
    lazy val userRepository = wire[SimpleUserRepository]
  }
}
