-- | Shared types for Yamux session management.
--
-- Types follow the HashiCorp yamux spec.md and docs/06-multiplexing.md.
-- SessionRole determines stream ID parity, StreamState tracks the
-- stream lifecycle state machine, and YamuxSession/YamuxStream hold
-- per-session/per-stream mutable state via STM.
module Network.LibP2P.Mux.Yamux.Types
  ( SessionRole (..)
  , StreamState (..)
  , YamuxError (..)
  , YamuxStream (..)
  , YamuxSession (..)
  ) where

import Control.Concurrent.STM (TMVar, TQueue, TVar)
import Data.ByteString (ByteString)
import qualified Data.Map.Strict as Map
import Data.Word (Word32)
import Network.LibP2P.Mux.Yamux.Frame (GoAwayCode, YamuxHeader)

-- | SessionRole determines stream ID parity (spec.md §Stream Identification).
-- Client uses odd IDs (1, 3, 5, ...), Server uses even IDs (2, 4, 6, ...).
data SessionRole = RoleClient | RoleServer
  deriving (Int -> SessionRole -> ShowS
[SessionRole] -> ShowS
SessionRole -> String
(Int -> SessionRole -> ShowS)
-> (SessionRole -> String)
-> ([SessionRole] -> ShowS)
-> Show SessionRole
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SessionRole -> ShowS
showsPrec :: Int -> SessionRole -> ShowS
$cshow :: SessionRole -> String
show :: SessionRole -> String
$cshowList :: [SessionRole] -> ShowS
showList :: [SessionRole] -> ShowS
Show, SessionRole -> SessionRole -> Bool
(SessionRole -> SessionRole -> Bool)
-> (SessionRole -> SessionRole -> Bool) -> Eq SessionRole
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SessionRole -> SessionRole -> Bool
== :: SessionRole -> SessionRole -> Bool
$c/= :: SessionRole -> SessionRole -> Bool
/= :: SessionRole -> SessionRole -> Bool
Eq)

-- | Stream state machine (spec.md §Stream Open/Close/Reset).
-- States map to the spec's lifecycle:
--   SYN sent/received -> Established -> FIN sent/received -> Closed
data StreamState
  = StreamSYNSent -- ^ SYN sent, awaiting ACK (initiator)
  | StreamSYNReceived -- ^ SYN received, awaiting local ACK (responder)
  | StreamEstablished -- ^ Both SYN/ACK exchanged, data flows
  | StreamLocalClose -- ^ Local FIN sent (half-closed)
  | StreamRemoteClose -- ^ Remote FIN received (half-closed)
  | StreamClosed -- ^ Both FIN'd
  | StreamReset -- ^ RST sent or received
  deriving (Int -> StreamState -> ShowS
[StreamState] -> ShowS
StreamState -> String
(Int -> StreamState -> ShowS)
-> (StreamState -> String)
-> ([StreamState] -> ShowS)
-> Show StreamState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StreamState -> ShowS
showsPrec :: Int -> StreamState -> ShowS
$cshow :: StreamState -> String
show :: StreamState -> String
$cshowList :: [StreamState] -> ShowS
showList :: [StreamState] -> ShowS
Show, StreamState -> StreamState -> Bool
(StreamState -> StreamState -> Bool)
-> (StreamState -> StreamState -> Bool) -> Eq StreamState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StreamState -> StreamState -> Bool
== :: StreamState -> StreamState -> Bool
$c/= :: StreamState -> StreamState -> Bool
/= :: StreamState -> StreamState -> Bool
Eq)

-- | Errors map to spec-defined conditions.
data YamuxError
  = YamuxProtocolError !String -- ^ Spec violation (e.g., invalid version, unknown frame type)
  | YamuxStreamClosed -- ^ Write/read on closed stream
  | YamuxStreamReset -- ^ RST received
  | YamuxSessionShutdown -- ^ GoAway received or session closed
  | YamuxGoAway !GoAwayCode -- ^ Remote sent GoAway with specific code
  deriving (Int -> YamuxError -> ShowS
[YamuxError] -> ShowS
YamuxError -> String
(Int -> YamuxError -> ShowS)
-> (YamuxError -> String)
-> ([YamuxError] -> ShowS)
-> Show YamuxError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> YamuxError -> ShowS
showsPrec :: Int -> YamuxError -> ShowS
$cshow :: YamuxError -> String
show :: YamuxError -> String
$cshowList :: [YamuxError] -> ShowS
showList :: [YamuxError] -> ShowS
Show, YamuxError -> YamuxError -> Bool
(YamuxError -> YamuxError -> Bool)
-> (YamuxError -> YamuxError -> Bool) -> Eq YamuxError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: YamuxError -> YamuxError -> Bool
== :: YamuxError -> YamuxError -> Bool
$c/= :: YamuxError -> YamuxError -> Bool
/= :: YamuxError -> YamuxError -> Bool
Eq)

-- | Per-stream state (spec.md §Flow Control: per-stream windows only).
data YamuxStream = YamuxStream
  { YamuxStream -> Word32
ysStreamId :: !Word32
  , YamuxStream -> TVar StreamState
ysState :: !(TVar StreamState)
  , YamuxStream -> TVar Word32
ysSendWindow :: !(TVar Word32) -- ^ Starts at 262144 (256 KiB)
  , YamuxStream -> TVar Word32
ysRecvWindow :: !(TVar Word32) -- ^ Starts at 262144 (256 KiB)
  , YamuxStream -> TQueue ByteString
ysRecvBuf :: !(TQueue ByteString) -- ^ Incoming data frames
  , YamuxStream -> TMVar ()
ysSendNotify :: !(TMVar ()) -- ^ Wakeup blocked writers on WindowUpdate
  , YamuxStream -> YamuxSession
ysSession :: !YamuxSession -- ^ Back-reference for frame sending
  }

-- | Session state.
data YamuxSession = YamuxSession
  { YamuxSession -> SessionRole
ysRole :: !SessionRole
  , YamuxSession -> TVar Word32
ysNextStreamId :: !(TVar Word32) -- ^ Next ID to allocate
  , YamuxSession -> TVar (Map Word32 YamuxStream)
ysStreams :: !(TVar (Map.Map Word32 YamuxStream)) -- ^ Active streams
  , YamuxSession -> TQueue YamuxStream
ysAcceptCh :: !(TQueue YamuxStream) -- ^ Inbound streams (max 256 pending)
  , YamuxSession -> TQueue (YamuxHeader, ByteString)
ysSendCh :: !(TQueue (YamuxHeader, ByteString)) -- ^ Outbound frame queue
  , YamuxSession -> TVar Bool
ysShutdown :: !(TVar Bool) -- ^ Local GoAway sent
  , YamuxSession -> TVar Bool
ysRemoteGoAway :: !(TVar Bool) -- ^ Remote GoAway received
  , YamuxSession -> TVar (Map Word32 (TMVar ()))
ysPings :: !(TVar (Map.Map Word32 (TMVar ()))) -- ^ Pending ping responses
  , YamuxSession -> TVar Word32
ysNextPingId :: !(TVar Word32)
  , YamuxSession -> ByteString -> IO ()
ysWrite :: !(ByteString -> IO ()) -- ^ Underlying transport write
  , YamuxSession -> Int -> IO ByteString
ysRead :: !(Int -> IO ByteString) -- ^ Underlying transport read exact N bytes
  }