{-# LANGUAGE  UndecidableInstances #-}
module IHP.ServerSideComponent.Controller.ComponentsController where

import IHP.ControllerPrelude
import IHP.ServerSideComponent.Types as SSC
import IHP.ServerSideComponent.ControllerFunctions as SSC

import qualified Data.Aeson as Aeson
import qualified Text.Blaze.Html.Renderer.Text as Blaze

instance (Component component controller, FromJSON controller) => WSApp (ComponentsController component) where
    initialState :: ComponentsController component
initialState = ComponentsController component
forall components. ComponentsController components
ComponentsController

    run :: IO ()
run = do
        let component
state :: component = component
forall state action. Component state action => state
SSC.initialState
        IORef (ComponentInstance component)
instanceRef <- ComponentInstance component
-> IO (IORef (ComponentInstance component))
forall a. a -> IO (IORef a)
newIORef (ComponentInstance :: forall state. state -> ComponentInstance state
ComponentInstance { component
$sel:state:ComponentInstance :: component
state :: component
state })
        let ?instanceRef = instanceRef

        component
nextState <- component -> IO component
forall state action.
(Component state action,
 ?instanceRef::IORef (ComponentInstance state),
 ?connection::Connection, ?context::ControllerContext,
 ?modelContext::ModelContext) =>
state -> IO state
componentDidMount component
state
        component -> IO ()
forall state action.
(?instanceRef::IORef (ComponentInstance state),
 ?connection::Connection, Component state action,
 ?context::ControllerContext) =>
state -> IO ()
SSC.setState component
nextState

        IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever do
            LByteString
actionPayload :: LByteString <- IO LByteString
forall a. (?connection::Connection, WebSocketsData a) => IO a
receiveData

            let theAction :: Either String controller
theAction = LByteString -> Either String controller
forall a. FromJSON a => LByteString -> Either String a
Aeson.eitherDecode @controller LByteString
actionPayload

            case Either String controller
theAction of
                Right controller
theAction -> do
                    component
currentState <- IO component
forall model b.
(HasField "state" model b, ?instanceRef::IORef model) =>
IO b
SSC.getState

                    component
nextState <- component -> controller -> IO component
forall state action.
(Component state action,
 ?instanceRef::IORef (ComponentInstance state),
 ?connection::Connection, ?context::ControllerContext,
 ?modelContext::ModelContext) =>
state -> action -> IO state
SSC.action component
currentState controller
theAction
                    component -> IO ()
forall state action.
(?instanceRef::IORef (ComponentInstance state),
 ?connection::Connection, Component state action,
 ?context::ControllerContext) =>
state -> IO ()
SSC.setState component
nextState
                Left String
error -> Text -> IO ()
putStrLn (String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs String
error)