{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeSynonymInstances   #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE ScopedTypeVariables    #-}
{-# LANGUAGE TemplateHaskell        #-}
module Data.Vitals where

import qualified Prelude

import           Control.Lens           (makeLenses)
import           Data.HasTime           (HasTime(..))
import           Data.Time              (UTCTime)
import           Data.Time.Format       ()
import           Data.Time.LocalTime    ()
import           Numeric.Units.Dimensional.Prelude



data Weight = Weight {
      _wTime :: UTCTime
    , _wWeight :: Mass Float
    } deriving (Eq, Show)

instance HasTime Weight where
    time' elt_fn w =
        (\t' -> w { _wTime = t' }) <$> elt_fn (_wTime w)

averageWeight :: [Weight] -> Mass Float
averageWeight ws = average (\a -> _wWeight a /~ kilo gram) ws *~ kilo gram

-- rAverageWeight :: [Weight] -> Weight
-- rAverageWeight ws = rAverage (\a -> a /~ kilo gram) ws *~ kilo gram

-- weightChange :: Weight -> Weight -> Weight
-- weightChange w1 w2 = w1 - w2


data BloodPressure = BloodPressure {
          _bpTime :: UTCTime
        , _bpSystolic :: Int
        , _bpDiastolic :: Int
        , _bpPulse :: Int
    } deriving (Eq, Show)


-- averageBP :: [BloodPressure] -> BloodPressure
-- averageBP = averageBP_ average
 
 
-- rAverageBP :: [BloodPressure] -> BloodPressure
-- rAverageBP = averageBP_ rAverage


-- averageBP_ :: forall t c. Num c => ((BloodPressure -> c) -> t -> Float) -> t -> BloodPressure
-- averageBP_ avg bps =
--   let avgSystolic = round (avg (fromIntegral . bpSystolic) bps :: Float)
--       avgDiastolic = round (avg (fromIntegral . bpDiastolic) bps :: Float)
--       avgPulse = round (avg (fromIntegral . bpPulse) bps :: Float)
--   in BloodPressure avgSystolic avgDiastolic avgPulse


average :: Fractional a => (b -> a) -> [b] -> a
average field bps = Prelude.sum (fmap field bps) Prelude./ fromIntegral (length bps)


-- rAverage :: forall a b. Fractional a => (b -> a) -> [b] -> a
-- rAverage func = ravg Nothing . fmap func
--     where
--     f :: a -> a -> a
--     f b q = b Prelude.+ 0.1 Prelude.* (q Prelude.- b)
--     ravg :: Maybe a -> [a] -> a
--     ravg Nothing [] = 0.0
--     ravg Nothing (w:ws) = ravg (Just w) ws
--     ravg (Just base) [] = base
--     ravg (Just base) (w:ws) = ravg (Just $ f base w) ws


runningAverage :: (Show a, Fractional a) => [a] -> [a]
runningAverage [] = [0.0]
runningAverage [x] = [x]
runningAverage (x:rst) =
    let (prev:lst) = runningAverage rst in (prev Prelude.+ 0.1 Prelude.* (x Prelude.- prev)):prev:lst

makeLenses ''Weight
makeLenses ''BloodPressure

