-- |
-- Module      : Harmonic.Interface.Tidal.OctatripentatonicT
-- Description : Live-coding helpers for the octatripentatonic framework
--
-- Pretty-printers for inspecting the strata \/ tristrata state of a 'Harmonic.Framework.Builder.genP'-
-- generated 'Harmonic.Rules.Types.ProgressionContext.ProgressionContext' at the REPL during a live session. No
-- semantic behaviour — purely diagnostic output for humans.
--
-- @
-- s \<- seek \"*\" $ len 8 $ entropy 0.3 $ genI
-- genPReport s
-- @
--
-- Use these at the REPL between takes to see which strata and tristrata the
-- walk actually visited, rather than re-reading the generation trace.

module Harmonic.Interface.Tidal.OctatripentatonicT
  ( renderTristrataReport
  , genPReport
  ) where

import Data.Foldable (toList)
import Data.List (intercalate)

import qualified Harmonic.Rules.Types.Scale as Sc
import qualified Harmonic.Rules.Types.ProgressionContext as PC

-- |Render a multi-line report of the per-bar provenance of a
-- 'Harmonic.Rules.Types.ProgressionContext.ProgressionContext': for each bar, the tristrata index, its three strata,
-- and the selected strata for that bar. Returns 'Nothing' when the context
-- has no provenance (e.g., a legacy 'Harmonic.Framework.Builder.gen' result).
renderTristrataReport :: PC.ProgressionContext -> Maybe String
renderTristrataReport :: ProgressionContext -> Maybe String
renderTristrataReport ProgressionContext
pc = do
  Seq (Tristrata, StrataLabel)
prov <- ProgressionContext -> Maybe (Seq (Tristrata, StrataLabel))
PC.pcProvenance ProgressionContext
pc
  let rows :: [String]
rows = (Int -> (Tristrata, StrataLabel) -> String)
-> [Int] -> [(Tristrata, StrataLabel)] -> [String]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> (Tristrata, StrataLabel) -> String
forall {a} {a}. (Show a, Show a) => a -> (Tristrata, a) -> String
renderBar [Int
1 :: Int ..] (Seq (Tristrata, StrataLabel) -> [(Tristrata, StrataLabel)]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq (Tristrata, StrataLabel)
prov)
      hdr :: String
hdr  = String
"bar  tristrata              strata"
      sep :: String
sep  = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
hdr) Char
'-'
  String -> Maybe String
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([String] -> String
unlines (String
hdr String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String
sep String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
rows))
  where
    renderBar :: a -> (Tristrata, a) -> String
renderBar a
i (Tristrata
t, a
s) =
      let idx :: String
idx = case Tristrata -> [(Tristrata, Int)] -> Maybe Int
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Tristrata
t [(Tristrata, Int)]
indexedTristratas of
                  Just Int
n  -> Int -> String
forall a. Show a => a -> String
show Int
n
                  Maybe Int
Nothing -> String
"?"
          shown :: String
shown = StrataLabel -> String
forall a. Show a => a -> String
show (Tristrata -> StrataLabel
Sc.ts1 Tristrata
t) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ StrataLabel -> String
forall a. Show a => a -> String
show (Tristrata -> StrataLabel
Sc.ts2 Tristrata
t) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ StrataLabel -> String
forall a. Show a => a -> String
show (Tristrata -> StrataLabel
Sc.ts3 Tristrata
t)
      in Int -> String -> String
pad Int
4 (a -> String
forall a. Show a => a -> String
show a
i) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" #" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String -> String
pad Int
3 String
idx String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String -> String
pad Int
20 String
shown String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
s

    indexedTristratas :: [(Tristrata, Int)]
indexedTristratas = [Tristrata] -> [Int] -> [(Tristrata, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Tristrata]
Sc.validTristrata [Int
1 :: Int ..]
    pad :: Int -> String -> String
pad Int
n String
s = String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s)) Char
' '

-- |Live-coding helper: execute a 'Harmonic.Framework.Builder.genP'-style 'IO ProgressionContext' and
-- print a pretty tristrata report alongside the standard 'Show' output.
-- Useful at the REPL for sanity-checking a strata walk.
genPReport :: IO PC.ProgressionContext -> IO ()
genPReport :: IO ProgressionContext -> IO ()
genPReport IO ProgressionContext
action = do
  ProgressionContext
pc <- IO ProgressionContext
action
  String -> IO ()
putStrLn String
""
  case ProgressionContext -> Maybe String
renderTristrataReport ProgressionContext
pc of
    Just String
report -> String -> IO ()
putStr String
report
    Maybe String
Nothing     -> String -> IO ()
putStrLn String
"[no provenance — legacy gen result]"
  String -> IO ()
putStrLn String
""
  ProgressionContext -> IO ()
forall a. Show a => a -> IO ()
print ProgressionContext
pc