module Roller.Core (main) where

import Roller.Types
import Roller.Parse
import Roller.CLI

import System.Environment (getArgs)
import System.Random (randomRIO)
import Control.Applicative
import Control.Monad (join, replicateM, replicateM_)
import Data.Word

positiveRoll :: Word8 -> IO Integer
positiveRoll x = randomRIO $ (1, fromIntegral x)

negativeRoll :: Word8 -> IO Integer
negativeRoll x = (*(-1)) <$> positiveRoll x

positiveRolls :: Word8 -> Word8 -> IO [Integer]
positiveRolls x y = replicateM (fromIntegral x) . positiveRoll $ y

negativeRolls :: Word8 -> Word8 -> IO [Integer]
negativeRolls x y = replicateM (fromIntegral x) . negativeRoll $ y

rolls :: [DiceExpression] -> IO [Integer]
rolls expressions = foldl (\x y -> (++) <$> x <*> (extractDiceExpressionValue y)) (pure []) expressions

extractDiceExpressionValue :: DiceExpression -> IO [Integer]
extractDiceExpressionValue expression =
  case expression of
    DieTerm x y -> positiveRolls x y
    AddedDieTerm x y -> positiveRolls x y
    SubtractedDieTerm x y -> negativeRolls x y
    ConstantTerm x -> return [fromIntegral x]
    AddedConstantTerm x -> return [fromIntegral x]
    SubtractedConstantTerm x -> return [(-1) * (fromIntegral x)]

rollEm :: CLI (IO ())
rollEm verbose n args = maybe parseFail rollMany (parse input)
  where
    input             = concat args
    rollMany          = replicateM_ n . rollOnce
    rollOnce exp      = summary <$> (rolls exp) >>= putStrLn
    summary           = if verbose then showVerbose else show . sum
    showVerbose       = (\x -> (show . sum $ x) ++ " " ++ show x)
    parseFail         = putStrLn $ "Could not parse \"" ++ input ++ "\" as dice expression!"

main :: IO ()
main = join . withOpts $ rollEm