import { FileSystem, HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse, Path } from "@effect/platform"
import { RpcServer } from "@effect/rpc"
import { CommonConfig } from "@website/common/config"
import { WebRpc, WebRpcSerializationDevelopment, WebRpcSerializationProduction } from "@website/common/webrpc"
import { Duration, Effect, flow, Layer } from "effect"
import { WebRpcLive } from "./webrpc"


const router = HttpRouter.empty

const makeWebRpcRoute = Effect.all([
    CommonConfig.webRpcHttpPath,
    RpcServer.toHttpApp(WebRpc),
]).pipe(
    Effect.map(([path, app]) => HttpRouter.mountApp(path, app)),
    Effect.provide(WebRpcLive),
)

const makeProductionWebappRoute = Effect.fnUntraced(function*(route: HttpRouter.PathInput) {
    const path = yield* Path.Path
    const fs = yield* FileSystem.FileSystem
    const dist = path.join(yield* path.fromFileUrl(new URL(".", import.meta.resolve("@website/webapp"))), "dist")

    return HttpRouter.all(route, Effect.gen(function*() {
        const req = yield* HttpServerRequest.HttpServerRequest
        const source = path.join(dist, req.url)
        const exists = yield* fs.stat(source).pipe(
            Effect.andThen(stat => stat.type === "File"),
            Effect.catchAll(() => Effect.succeed(false)),
        )

        return yield* HttpServerResponse.setHeader(
            yield* HttpServerResponse.file(exists ? source : path.join(dist, "index.html")),
            "Cache-Control",
            `public, max-age=${Duration.toSeconds("365 days")}, immutable`
        )
    }))
})


export const HttpAppDevelopment = Layer.unwrapScoped(Effect.gen(function*() {
    return router.pipe(
        yield* Effect.provide(makeWebRpcRoute, WebRpcSerializationDevelopment),
        HttpServer.serve(flow(HttpMiddleware.logger, HttpMiddleware.xForwardedHeaders)),
        HttpServer.withLogAddress,
    )
}))

export const HttpAppProduction = Layer.unwrapScoped(Effect.gen(function*() {
    return router.pipe(
        yield* Effect.provide(makeWebRpcRoute, WebRpcSerializationProduction),
        yield* makeProductionWebappRoute("*"),
        HttpServer.serve(HttpMiddleware.xForwardedHeaders),
        HttpServer.withLogAddress,
    )
}))
