{-# 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 = forall {k} (components :: k). ComponentsController components
ComponentsController

    run :: (?state::IORef (ComponentsController component),
 ?context::ControllerContext,
 ?applicationContext::ApplicationContext,
 ?modelContext::ModelContext, ?connection::Connection) =>
IO ()
run = do
        let component
state :: component = forall state action. Component state action => state
SSC.initialState
        IORef (ComponentInstance component)
instanceRef <- forall a. a -> IO (IORef a)
newIORef (ComponentInstance { component
$sel:state:ComponentInstance :: component
state :: component
state })
        let ?instanceRef = IORef (ComponentInstance component)
instanceRef

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

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

            let theAction :: Either String controller
theAction = 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 <- forall {a} {b}.
(HasField "state" a b, ?instanceRef::IORef a) =>
IO b
SSC.getState

                    component
nextState <- 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
                    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 (forall a b. ConvertibleStrings a b => a -> b
cs String
error)