package eu.xeppaka.scalalearn

import org.bson.codecs.configuration.{CodecProvider, CodecRegistry}
import org.mongodb.scala.bson.codecs.Macros._
import org.bson.codecs.configuration.CodecRegistries.{fromCodecs, fromProviders, fromRegistries}
import org.bson.codecs.{Codec, DecoderContext, EncoderContext}
import org.bson.{BsonReader, BsonWriter}
import org.mongodb.scala.MongoClient
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
import scalapb.{GeneratedEnum, GeneratedEnumCompanion}

import scala.concurrent.Await
import scala.concurrent.duration._
import scala.reflect._

object Main7 {
  class ProtoEnumCodecProvider extends CodecProvider {
    override def get[T](clazz: Class[T], registry: CodecRegistry): Codec[T] = {
      val ass = classOf[GeneratedEnum].isAssignableFrom(clazz)
      if (ass) {
        new ProtoEnumCodec(clazz.asInstanceOf[Class[GeneratedEnum]]).asInstanceOf[Codec[T]]
      } else {
        null
      }
    }
  }

  class ProtoEnumCodec(clazz: Class[GeneratedEnum]) extends Codec[GeneratedEnum] {
    override def decode(reader: BsonReader, decoderContext: DecoderContext): GeneratedEnum = {
      val method = clazz.getDeclaredMethod("fromName", classOf[String])
      method.invoke(clazz, reader.readString()).asInstanceOf[Option[GeneratedEnum]].get
    }
    override def encode(writer: BsonWriter, value: GeneratedEnum, encoderContext: EncoderContext): Unit = writer.writeString(value.name)
    override def getEncoderClass: Class[GeneratedEnum] = clazz
  }

  case class UseEnum(
    status1: Status,
    status2: Status
  )

  def main(args: Array[String]): Unit = {
    val codecRegistry = fromRegistries(fromProviders(classOf[UseEnum], new ProtoEnumCodecProvider), DEFAULT_CODEC_REGISTRY)
    val client = MongoClient()
    val db = client.getDatabase("classtag-test").withCodecRegistry(codecRegistry)
    val status = db.getCollection[UseEnum]("statuses")

    //Await.result(status.insertOne(UseEnum(Status.OPEN, Status.BLOCKED_ALL)).toFuture(), 1.second)
    //Await.result(status.insertOne(Status.BLOCKED_ALL).toFuture(), 1.second)
    val res = Await.result(status.find().toFuture(), 1.second)
    println(res.head.status1)
  }
}
