module Spectator.HealthCheck

open System
open Spectator.Core
open Y2k.EventBus

type HealthCheckRequested =
    | HealthCheckRequested of Guid
    interface Event

type SendHealthCheckResponse =
    | SendHealthCheckResponse of Guid
    interface Command

let handleEvent (HealthCheckRequested id) : Command list =
    [ SendHealthCheckResponse id ]

open System.Net

type State =
    private
        { state: Map<Guid, HttpListenerContext> Atom.IAtom }

let init () = { state = Atom.atom Map.empty }

let private sendResponseToClient (text: string) (ctx: HttpListenerContext) =
    async {
        use _ = ctx.Response
        let bytes = Text.Encoding.UTF8.GetBytes text

        do! ctx.Response.OutputStream.WriteAsync(bytes, 0, bytes.Length) |> Async.AwaitTask
    }

let handleCmd { state = atom } (cmd: Command) =
    match cmd with
    | :? SendHealthCheckResponse as SendHealthCheckResponse id ->
        atom.dispatch (fun db -> Map.remove id db, Map.tryFind id db)
        |> Option.iter (sendResponseToClient "OK" >> Async.Start)
    | _ -> ()

let main { state = atom } (dispatch: Event -> unit) =
    async {
        let listener = new HttpListener()
        listener.Prefixes.Add "http://localhost:8888/"
        listener.Start()

        while true do
            let! ctx = listener.GetContextAsync()

            let id = Guid.NewGuid()
            atom.update (Map.add id ctx)

            dispatch (HealthCheckRequested id)
    }
