startServ
  :: (HasPierConfig e, HasLogFunc e, HasMultiEyreApi e, HasNetworkConfig e)
  => Ship
  -> Bool
  -> HttpServerConf
  -> (EvErr -> STM ())
  -> (Text -> RIO e ())
  -> IO ()
  -> KingSubsite
  -> RIO e Serv
startServ who isFake conf plan stderr onFatal sub = do
  logInfo (displayShow ("EYRE", "startServ"))

  multi <- view multiEyreApiL

  let vLive = meaLive multi

  srvId <- io $ ServId . UV . fromIntegral <$> (randomIO :: IO Word32)

  let mTls = hscSecure conf >>= parseTlsConfig

  mCre <- mTls & \case
   Nothing -> pure Nothing
   Just tc -> configCreds tc & \case
     Right rs -> pure (Just (tc, rs))
     Left err -> do
       logError "Couldn't Load TLS Credentials."
       pure Nothing

  ptt <- httpServerPorts isFake

  {-
    TODO If configuration requests a redirect, get the HTTPS port (if
    configuration specifies a specific port, use that. Otherwise, wait
    for the HTTPS server to start and then use the port that it chose).
    and run an HTTP server that simply redirects to the HTTPS server.
  -}
  let secRedi = Nothing

  let soHost :: SockOpts -> ServHost
      soHost so = if soLocalhost so then SHLocalhost else SHAnyHostOk

  noHttp  <- view (networkConfigL . ncNoHttp)
  noHttps <- view (networkConfigL . ncNoHttps)

  let reqEvFailed _ = pure ()

  let onReq :: WhichServer -> Ship -> Word64 -> ReqInfo -> STM ()
      onReq which _ship reqId reqInfo =
        plan $ EvErr (requestEvent srvId which reqId reqInfo) reqEvFailed

  let onKilReq :: Ship -> Word64 -> STM ()
      onKilReq _ship = plan . cancelEv srvId . fromIntegral

  logInfo (displayShow ("EYRE", "joinMultiEyre", who, mTls, mCre))

  atomically (joinMultiEyre multi who mCre onReq onKilReq sub)

  logInfo $ displayShow ("EYRE", "Starting loopback server")
  lop <- serv vLive onFatal $ ServConf
    { scHost = soHost (pttLop ptt)
    , scPort = soWhich (pttLop ptt)
    , scRedi = Nothing
    , scFake = False
    , scType = STHttp who sub $ ReqApi
        { rcReq = onReq Loopback
        , rcKil = onKilReq
        }
    }

  logInfo $ displayShow ("EYRE", "Starting insecure server")
  ins <- serv vLive onFatal $ ServConf
    { scHost = soHost (pttIns ptt)
    , scPort = soWhich (pttIns ptt)
    , scRedi = secRedi
    , scFake = noHttp
    , scType = STHttp who sub $ ReqApi
        { rcReq = onReq Insecure
        , rcKil = onKilReq
        }
    }

  mSec <- for mTls $ \tls -> do
    logInfo "Starting secure server"
    serv vLive onFatal $ ServConf
      { scHost = soHost (pttSec ptt)
      , scPort = soWhich (pttSec ptt)
      , scRedi = Nothing
      , scFake = noHttps
      , scType = STHttps who tls sub $ ReqApi
          { rcReq = onReq Secure
          , rcKil = onKilReq
          }
      }

  pierPath <- view pierPathL

  lopPor <- atomically (fmap fromIntegral $ saPor lop)
  insPor <- atomically (fmap fromIntegral $ saPor ins)
  secPor <- for mSec (fmap fromIntegral . atomically . saPor)

  let por = Ports secPor insPor lopPor
      fil = pierPath <> "/.http.ports"

  logInfo $ displayShow ("EYRE", "All Servers Started.", srvId, por, fil)
  for secPor $ \p ->
    stderr ("http: secure web interface live on https://localhost:" <> tshow p)
  stderr ("http: web interface live on http://localhost:" <> tshow insPor)
  stderr ("http: loopback live on http://localhost:" <> tshow lopPor)

  pure (Serv srvId conf lop ins mSec por fil vLive)


-- Eyre Driver -----------------------------------------------------------------
startServ
  :: (HasPierConfig e, HasLogFunc e, HasMultiEyreApi e, HasNetworkConfig e)
  => Ship
  -> Bool
  -> HttpServerConf
  -> (EvErr -> STM ())
  -> (Text -> RIO e ())
  -> IO ()
  -> KingSubsite
  -> RIO e Serv
startServ who isFake conf plan stderr onFatal sub = do
  logInfo (displayShow ("EYRE", "startServ"))

  multi <- view multiEyreApiL

  let vLive = meaLive multi

  srvId <- io $ ServId . UV . fromIntegral <$> (randomIO :: IO Word32)

  let mTls = hscSecure conf >>= parseTlsConfig

  mCre <- mTls & \case
   Nothing -> pure Nothing
   Just tc -> configCreds tc & \case
     Right rs -> pure (Just (tc, rs))
     Left err -> do
       logError "Couldn't Load TLS Credentials."
       pure Nothing

  ptt <- httpServerPorts isFake

  {-
    TODO If configuration requests a redirect, get the HTTPS port (if
    configuration specifies a specific port, use that. Otherwise, wait
    for the HTTPS server to start and then use the port that it chose).
    and run an HTTP server that simply redirects to the HTTPS server.
  -}
  let secRedi = Nothing

  let soHost :: SockOpts -> ServHost
      soHost so = if soLocalhost so then SHLocalhost else SHAnyHostOk

  noHttp  <- view (networkConfigL . ncNoHttp)
  noHttps <- view (networkConfigL . ncNoHttps)

  let reqEvFailed _ = pure ()

  let onReq :: WhichServer -> Ship -> Word64 -> ReqInfo -> STM ()
      onReq which _ship reqId reqInfo =
        plan $ EvErr (requestEvent srvId which reqId reqInfo) reqEvFailed

  let onKilReq :: Ship -> Word64 -> STM ()
      onKilReq _ship = plan . cancelEv srvId . fromIntegral

  logInfo (displayShow ("EYRE", "joinMultiEyre", who, mTls, mCre))

  atomically (joinMultiEyre multi who mCre onReq onKilReq sub)

  logInfo $ displayShow ("EYRE", "Starting loopback server")
  lop <- serv vLive onFatal $ ServConf
    { scHost = soHost (pttLop ptt)
    , scPort = soWhich (pttLop ptt)
    , scRedi = Nothing
    , scFake = False
    , scType = STHttp who sub $ ReqApi
        { rcReq = onReq Loopback
        , rcKil = onKilReq
        }
    }

  logInfo $ displayShow ("EYRE", "Starting insecure server")
  ins <- serv vLive onFatal $ ServConf
    { scHost = soHost (pttIns ptt)
    , scPort = soWhich (pttIns ptt)
    , scRedi = secRedi
    , scFake = noHttp
    , scType = STHttp who sub $ ReqApi
        { rcReq = onReq Insecure
        , rcKil = onKilReq
        }
    }

  mSec <- for mTls $ \tls -> do
    logInfo "Starting secure server"
    serv vLive onFatal $ ServConf
      { scHost = soHost (pttSec ptt)
      , scPort = soWhich (pttSec ptt)
      , scRedi = Nothing
      , scFake = noHttps
      , scType = STHttps who tls sub $ ReqApi
          { rcReq = onReq Secure
          , rcKil = onKilReq
          }
      }

  pierPath <- view pierPathL

  lopPor <- atomically (fmap fromIntegral $ saPor lop)
  insPor <- atomically (fmap fromIntegral $ saPor ins)
  secPor <- for mSec (fmap fromIntegral . atomically . saPor)

  let por = Ports secPor insPor lopPor
      fil = pierPath <> "/.http.ports"

  logInfo $ displayShow ("EYRE", "All Servers Started.", srvId, por, fil)
  for secPor $ \p ->
    stderr ("http: secure web interface live on https://localhost:" <> tshow p)
  stderr ("http: web interface live on http://localhost:" <> tshow insPor)
  stderr ("http: loopback live on http://localhost:" <> tshow lopPor)

  pure (Serv srvId conf lop ins mSec por fil vLive)


-- Eyre Driver -----------------------------------------------------------------
startServ who isFake conf plan stderr onFatal sub = do
  logInfo (displayShow ("EYRE", "startServ"))

  multi <- view multiEyreApiL

  let vLive = meaLive multi

  srvId <- io $ ServId . UV . fromIntegral <$> (randomIO :: IO Word32)

  let mTls = hscSecure conf >>= parseTlsConfig

  mCre <- mTls & \case
   Nothing -> pure Nothing
   Just tc -> configCreds tc & \case
     Right rs -> pure (Just (tc, rs))
     Left err -> do
       logError "Couldn't Load TLS Credentials."
       pure Nothing

  ptt <- httpServerPorts isFake

  {-
    TODO If configuration requests a redirect, get the HTTPS port (if
    configuration specifies a specific port, use that. Otherwise, wait
    for the HTTPS server to start and then use the port that it chose).
    and run an HTTP server that simply redirects to the HTTPS server.
  -}
  let secRedi = Nothing

  let soHost :: SockOpts -> ServHost
      soHost so = if soLocalhost so then SHLocalhost else SHAnyHostOk

  noHttp  <- view (networkConfigL . ncNoHttp)
  noHttps <- view (networkConfigL . ncNoHttps)

  let reqEvFailed _ = pure ()

  let onReq :: WhichServer -> Ship -> Word64 -> ReqInfo -> STM ()
      onReq which _ship reqId reqInfo =
        plan $ EvErr (requestEvent srvId which reqId reqInfo) reqEvFailed

  let onKilReq :: Ship -> Word64 -> STM ()
      onKilReq _ship = plan . cancelEv srvId . fromIntegral

  logInfo (displayShow ("EYRE", "joinMultiEyre", who, mTls, mCre))

  atomically (joinMultiEyre multi who mCre onReq onKilReq sub)

  logInfo $ displayShow ("EYRE", "Starting loopback server")
  lop <- serv vLive onFatal $ ServConf
    { scHost = soHost (pttLop ptt)
    , scPort = soWhich (pttLop ptt)
    , scRedi = Nothing
    , scFake = False
    , scType = STHttp who sub $ ReqApi
        { rcReq = onReq Loopback
        , rcKil = onKilReq
        }
    }

  logInfo $ displayShow ("EYRE", "Starting insecure server")
  ins <- serv vLive onFatal $ ServConf
    { scHost = soHost (pttIns ptt)
    , scPort = soWhich (pttIns ptt)
    , scRedi = secRedi
    , scFake = noHttp
    , scType = STHttp who sub $ ReqApi
        { rcReq = onReq Insecure
        , rcKil = onKilReq
        }
    }

  mSec <- for mTls $ \tls -> do
    logInfo "Starting secure server"
    serv vLive onFatal $ ServConf
      { scHost = soHost (pttSec ptt)
      , scPort = soWhich (pttSec ptt)
      , scRedi = Nothing
      , scFake = noHttps
      , scType = STHttps who tls sub $ ReqApi
          { rcReq = onReq Secure
          , rcKil = onKilReq
          }
      }

  pierPath <- view pierPathL

  lopPor <- atomically (fmap fromIntegral $ saPor lop)
  insPor <- atomically (fmap fromIntegral $ saPor ins)
  secPor <- for mSec (fmap fromIntegral . atomically . saPor)

  let por = Ports secPor insPor lopPor
      fil = pierPath <> "/.http.ports"

  logInfo $ displayShow ("EYRE", "All Servers Started.", srvId, por, fil)
  for secPor $ \p ->
    stderr ("http: secure web interface live on https://localhost:" <> tshow p)
  stderr ("http: web interface live on http://localhost:" <> tshow insPor)
  stderr ("http: loopback live on http://localhost:" <> tshow lopPor)

  pure (Serv srvId conf lop ins mSec por fil vLive)


-- Eyre Driver -----------------------------------------------------------------