module Chiasma.Data.Panes where

import Chiasma.Class.CmdArgs (cmdArgs)
import qualified Chiasma.Codec as Codec
import Chiasma.Codec (TmuxCodec, multi, single)
import qualified Chiasma.Data.DecodeError as DecodeFailure
import Chiasma.Data.DecodeError (DecodeError (DecodeError))
import qualified Chiasma.Data.PaneSelection as PaneSelection
import Chiasma.Data.PaneSelection (PaneSelection)
import qualified Chiasma.Data.Target as Target
import Chiasma.Data.TmuxId (PaneId)
import Chiasma.Data.TmuxQuery (TmuxQuery)
import Chiasma.Data.TmuxRequest (TmuxRequest (TmuxRequest))
import Chiasma.Data.TmuxResponse (TmuxResponse (TmuxResponse))
import Chiasma.Data.WithPaneId (WithPaneId (WithPaneId))
import Chiasma.Effect.TmuxApi (TmuxApi)

  |A ' TmuxApi ' command for listing panes , with different query criteria .
  The constructors taking a ' PaneSelection ' list all panes that are present in the selected scope , but may constrain
-- the return value.
-- The constructors 'Get' and 'Find' return only the pane with the requested ID.
data Panes (p :: Type) (a :: Type) :: Type where
  -- |Return all panes covered by the selection.
  List :: PaneSelection -> Panes p [p]
  -- |Return one pane covered by the selection, fail if there is none.
  First :: PaneSelection -> Panes p p
  |Return one pane covered by the selection , fail if there is none or more than one .
  One :: PaneSelection -> Panes p p
  -- |Return the pane with the specified ID, fail if there is none.
  Get :: PaneId -> Panes p p
  -- |Return the pane with the specified ID if it exists.
  Find :: PaneId -> Panes p (Maybe p)

type TmuxPanes p =
  TmuxApi (Panes p)

query ::
  ∀ p a .
  TmuxCodec p =>
  Panes p a ->
  TmuxQuery
query _ =
  Codec.query @p

selection :: Panes p a -> PaneSelection
selection = \case
  List ps -> ps
  First ps -> ps
  One ps -> ps
  Get i -> PaneSelection.InWindow (Target.Pane i)
  Find _ -> PaneSelection.All

request ::
  Panes p a ->
  TmuxQuery ->
  TmuxRequest
request (selection -> s) =
  TmuxRequest "list-panes" (cmdArgs s) . Just

encode ::
  ∀ p a .
  TmuxCodec p =>
  Panes p a ->
  TmuxRequest
encode (Get i) =
  request (Get i) (Codec.query @(WithPaneId p))
encode (Find i) =
  request (Find i) (Codec.query @(WithPaneId p))
encode cmd =
  request cmd (query cmd)

sameId :: PaneId -> WithPaneId a -> Maybe a
sameId target (WithPaneId paneId p)
  | target == paneId = Just p
  | otherwise = Nothing

paneById ::
  TmuxCodec p =>
  PaneId ->
  [Text] ->
  Either DecodeError (Maybe p)
paneById paneId out = do
  firstJust (sameId paneId) <$> multi out

decode ::
  ∀ p a .
  TmuxCodec p =>
  TmuxResponse ->
  Panes p a ->
  Either DecodeError a
decode (TmuxResponse out) = \case
  List _ ->
    multi out
  First _ ->
    multi out >>= \case
      [] -> Left (DecodeError out DecodeFailure.TooFewFields)
      a : _ -> Right a
  One _ ->
    single out
  Get paneId -> do
    ps <- multi @(WithPaneId p) out
    maybeToRight (DecodeError out DecodeFailure.TargetMissing) (firstJust (sameId paneId) ps)
  Find paneId -> do
    ps <- multi @(WithPaneId p) out
    pure (firstJust (sameId paneId) ps)

 the return value.
 The constructors 'Get' and 'Find' return only the pane with the requested ID.
 |Return all panes covered by the selection.
 |Return one pane covered by the selection, fail if there is none.
 |Return the pane with the specified ID, fail if there is none.
 |Return the pane with the specified ID if it exists.
module Chiasma.Data.Panes where

import Chiasma.Class.CmdArgs (cmdArgs)
import qualified Chiasma.Codec as Codec
import Chiasma.Codec (TmuxCodec, multi, single)
import qualified Chiasma.Data.DecodeError as DecodeFailure
import Chiasma.Data.DecodeError (DecodeError (DecodeError))
import qualified Chiasma.Data.PaneSelection as PaneSelection
import Chiasma.Data.PaneSelection (PaneSelection)
import qualified Chiasma.Data.Target as Target
import Chiasma.Data.TmuxId (PaneId)
import Chiasma.Data.TmuxQuery (TmuxQuery)
import Chiasma.Data.TmuxRequest (TmuxRequest (TmuxRequest))
import Chiasma.Data.TmuxResponse (TmuxResponse (TmuxResponse))
import Chiasma.Data.WithPaneId (WithPaneId (WithPaneId))
import Chiasma.Effect.TmuxApi (TmuxApi)

  |A ' TmuxApi ' command for listing panes , with different query criteria .
  The constructors taking a ' PaneSelection ' list all panes that are present in the selected scope , but may constrain
data Panes (p :: Type) (a :: Type) :: Type where
  List :: PaneSelection -> Panes p [p]
  First :: PaneSelection -> Panes p p
  |Return one pane covered by the selection , fail if there is none or more than one .
  One :: PaneSelection -> Panes p p
  Get :: PaneId -> Panes p p
  Find :: PaneId -> Panes p (Maybe p)

type TmuxPanes p =
  TmuxApi (Panes p)

query ::
  ∀ p a .
  TmuxCodec p =>
  Panes p a ->
  TmuxQuery
query _ =
  Codec.query @p

selection :: Panes p a -> PaneSelection
selection = \case
  List ps -> ps
  First ps -> ps
  One ps -> ps
  Get i -> PaneSelection.InWindow (Target.Pane i)
  Find _ -> PaneSelection.All

request ::
  Panes p a ->
  TmuxQuery ->
  TmuxRequest
request (selection -> s) =
  TmuxRequest "list-panes" (cmdArgs s) . Just

encode ::
  ∀ p a .
  TmuxCodec p =>
  Panes p a ->
  TmuxRequest
encode (Get i) =
  request (Get i) (Codec.query @(WithPaneId p))
encode (Find i) =
  request (Find i) (Codec.query @(WithPaneId p))
encode cmd =
  request cmd (query cmd)

sameId :: PaneId -> WithPaneId a -> Maybe a
sameId target (WithPaneId paneId p)
  | target == paneId = Just p
  | otherwise = Nothing

paneById ::
  TmuxCodec p =>
  PaneId ->
  [Text] ->
  Either DecodeError (Maybe p)
paneById paneId out = do
  firstJust (sameId paneId) <$> multi out

decode ::
  ∀ p a .
  TmuxCodec p =>
  TmuxResponse ->
  Panes p a ->
  Either DecodeError a
decode (TmuxResponse out) = \case
  List _ ->
    multi out
  First _ ->
    multi out >>= \case
      [] -> Left (DecodeError out DecodeFailure.TooFewFields)
      a : _ -> Right a
  One _ ->
    single out
  Get paneId -> do
    ps <- multi @(WithPaneId p) out
    maybeToRight (DecodeError out DecodeFailure.TargetMissing) (firstJust (sameId paneId) ps)
  Find paneId -> do
    ps <- multi @(WithPaneId p) out
    pure (firstJust (sameId paneId) ps)
