package zio.http

import scala.scalajs.js

import zio._
import zio.test._

import zio.http.internal.FetchBodyBatched

object JSClientSpec extends ZIOSpecDefault {

  private val serverLayer: ZLayer[Any, Throwable, (js.Dynamic, Int)] = ZLayer.scoped {
    ZIO.acquireRelease {
      ZIO.async[Any, Throwable, (js.Dynamic, Int)] { callback =>
        val http          = js.Dynamic.global.require("http")
        val server        = http.createServer { (_: js.Dynamic, res: js.Dynamic) =>
          res.writeHead(200, js.Dictionary("Content-Type" -> "text/html"))
          res.end("<!doctype html><html><body>Hello</body></html>")
          ()
        }
        val _: js.Dynamic = server.listen(
          0,
          { () =>
            val port = server.address().port.asInstanceOf[Int]
            callback(ZIO.succeed((server, port)))
          },
        )
      }
    } { case (server, _) =>
      ZIO.succeed(server.close())
    }
  }

  private val portLayer: ZLayer[Any, Throwable, Int] =
    serverLayer.map(env => ZEnvironment(env.get[(js.Dynamic, Int)]._2))

  override def spec: Spec[TestEnvironment with Scope, Any] =
    suite("JSClientSpec")(
      suite("HTTP")(
        test("Get without User Agent") {
          for {
            port <- ZIO.service[Int]
            res  <- (for {
              response <- ZIO.serviceWithZIO[Client] {
                _.url(url"http://localhost/").port(port).batched.get("")
              }
              string   <- response.body.asString
            } yield (response, string))
              .provide(ZLayer.succeed(ZClient.Config.default.addUserAgentHeader(false)) >>> ZClient.live)
            (response, string) = res
          } yield assertTrue(
            response.status.isSuccess,
            response.body.isInstanceOf[FetchBodyBatched],
            string.startsWith("<!doctype html>"),
          )
        },
        test("Get with User Agent") {
          for {
            port <- ZIO.service[Int]
            res  <- (for {
              response <- ZIO.serviceWithZIO[Client] {
                _.url(url"http://localhost/").port(port).batched.get("")
              }
              string   <- response.body.asString
            } yield (response, string)).provide(ZClient.default)
            (response, string) = res
          } yield assertTrue(
            response.status.isSuccess,
            string.startsWith("<!doctype html>"),
          )
        },
      ),
//      suite("WebSocket")(
//        test("Echo") {
//          def sendChatMessage(message: String): ZIO[Queue[String], Throwable, Unit] =
//            ZIO.serviceWithZIO[Queue[String]](_.offer(message).unit)
//
//          def processQueue(channel: WebSocketChannel): ZIO[Queue[String], Throwable, Unit] = {
//            for {
//              queue <- ZIO.service[Queue[String]]
//              msg   <- queue.take
//              _     <- channel.send(Read(WebSocketFrame.Text(msg)))
//            } yield ()
//          }.forever.forkDaemon.unit
//
//          val webSocketHandler: ZIO[Queue[String] with Client with Scope, Throwable, Response] =
//            Handler.webSocket { channel =>
//              for {
//                _ <- sendChatMessage("Hello, World!")
//                _ <- processQueue(channel)
//                _ <- channel.receiveAll {
//                  case Read(WebSocketFrame.Text(text)) =>
//                    Console.printLine(s"Server: $text")
//                  case _                               =>
//                    ZIO.unit
//                }
//              } yield ()
//            }.connect("ws://localhost:8080/subscriptions")
//          for {
//            _     <- webSocketHandler
//            consoleMessages <- TestConsole.output
//          } yield assertTrue(consoleMessages.contains("Server: Hello, World!"))
//        }.provideSome[Scope & Client](ZLayer(Queue.bounded[String](100))),
//      ),
    ).provideShared(portLayer) @@ TestAspect.ifEnvSet("CI")
}
