{-# LANGUAGE FlexibleContexts  #-}

module Hrpg.Framework.Combat.EncounterData
      ( EncounterData (..)
      , doPlayerAction
      , doMobAction
      , getMob
      , getPlayer
      , updateMob
      , updatePlayer
      ) where

import Control.Monad.State
import Control.Monad.Random

import Hrpg.Framework.Combat.CombatAction
import Hrpg.Framework.Combat.CombatData
import Hrpg.Framework.Combat.CombatResult
import Hrpg.Framework.Combat.Dmg
import Hrpg.Framework.Combat.MeleeAttack
import Hrpg.Framework.Player
import Hrpg.Framework.Mobs.Mob

data EncounterData = EncounterData 
    { player :: Player
    , mob    :: Mob
    } deriving Show

getMob :: MonadState EncounterData m => m Mob 
getMob = do
  e <- get
  return (mob e)

getPlayer :: MonadState EncounterData m => m Player
getPlayer = do
  e <- get
  return (player e)

getPlayerCombatData :: MonadState EncounterData m => m CombatData
getPlayerCombatData = do
  p <- getPlayer
  return (playerCombatData p)

getMobCombatData :: MonadState EncounterData m => m CombatData
getMobCombatData = do
  m <- getMob
  return (mobCombatData m)

reduceMobHp :: MonadState EncounterData m => Int -> m ()
reduceMobHp x = do
  e <- get
  m <- getMob
  let hp = mobCurrentHp m
  let m' = m { mobCurrentHp = hp - x }
  put e { mob = m' }
  return ()

reducePlayerHp :: MonadState EncounterData m => Int -> m ()
reducePlayerHp x = do
  e <- get
  p <- getPlayer
  let hp = playerCurrentHp p
  let p' = p { playerCurrentHp = hp - x }
  put e { player = p' }
  return ()

updatePlayer :: MonadState EncounterData m => CombatResult -> m ()
updatePlayer (MeleeHit  (Dmg x)) = reducePlayerHp x
updatePlayer (MeleeCrit (Dmg x)) = reducePlayerHp x
updatePlayer _                   = return ()

updateMob :: MonadState EncounterData m => CombatResult -> m ()
updateMob (MeleeHit  (Dmg x)) = reduceMobHp x
updateMob (MeleeCrit (Dmg x)) = reduceMobHp x
updateMob _                   = return ()

doAction :: MonadRandom m => CombatAction -> CombatData -> CombatData -> m CombatResult
doAction MeleeAttack attacker defender = meleeAttack attacker defender

doPlayerAction :: (MonadState EncounterData m, MonadRandom m) => CombatAction -> m CombatResult
doPlayerAction action = do
  attacker <- getPlayerCombatData
  defender <- getMobCombatData
  doAction action attacker defender

doMobAction :: (MonadState EncounterData m, MonadRandom m) => CombatAction -> m CombatResult
doMobAction action = do
  attacker <- getMobCombatData
  defender <- getPlayerCombatData
  doAction action attacker defender 
