{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE NoImplicitPrelude      #-}
{-# LANGUAGE OverloadedStrings      #-}
{-# OPTIONS_GHC -fno-warn-orphans   #-}
module Health.Instances where

import Numeric.Units.Dimensional.Prelude hiding (Activity)

import           Data.HasTime
import           Data.Fitness.SetRep
import           Data.Fitness.TimeDistance
import           Data.Vitals
import           LuminescentDreams.Database.TimeSeries

import           Control.Lens   ((^.))
import           Data.Aeson


instance ToJSON Weight where
    toJSON w = object [ "date"      .= (w ^. wTime)
                      , "weight"    .= ((w ^. wWeight) /~ kilo gram)
                      ]

instance FromJSON Weight where
    parseJSON (Object obj) = Weight <$> obj .: "date" <*> ((*~ kilo gram) `fmap` (obj .: "weight"))
    parseJSON _ = mempty

instance Storable Weight where
    timestamp = (^. wTime)


instance ToJSON TimeDistance where
    toJSON td = object [ "date"     .= (td ^. tdTime)
                       , "activity" .= (td ^. tdActivity)
                       , "distance" .= ((/~ meter) <$> (td ^. tdDistance))
                       , "duration" .= ((/~ second) <$> (td ^. tdDuration))
                       , "comments" .= (td ^. tdComments)
                       ]

instance FromJSON TimeDistance where
    parseJSON (Object obj) = do
        date     <- obj .: "date"
        activity <- obj .: "activity"
        distance <- obj .:? "distance"  .!= Nothing
        duration <- obj .:? "duration"  .!= Nothing
        comments <- obj .:? "comments"  .!= Nothing
        pure $ TimeDistance date
                            activity
                            ((*~ meter) `fmap` distance)
                            ((*~ second) `fmap` duration)
                            comments
    parseJSON _ = mempty

instance ToJSON TimeDistanceActivity where
    toJSON Cycling = String "Cycling"
    toJSON Running = String "Running"

instance FromJSON TimeDistanceActivity where
    parseJSON (String "Cycling") = pure Cycling
    parseJSON (String "Running") = pure Running
    parseJSON _ = mempty

instance Storable TimeDistance where
    timestamp = (^. tdTime)


instance ToJSON SetRep where
    toJSON sr =
        object [ "date"     .= (sr ^. srTime)
               , "activity" .= (sr ^. srActivity)
               , "sets"     .= (sr ^. srSets)
               ]

instance FromJSON SetRep where
    parseJSON (Object obj) = do
        date     <- obj .: "date"
        activity <- obj .: "activity"
        sets     <- obj .: "sets"
        pure $ SetRep date activity (read `fmap` words sets)
    parseJSON _ = mempty

instance ToJSON SetRepActivity where
    toJSON Crunches = String "Crunches"
    toJSON Pushups = String "Pushups"
    toJSON Situps = String "Situps"

instance FromJSON SetRepActivity where
    parseJSON (String "Crunches") = pure Crunches
    parseJSON (String "Pushups")  = pure Pushups
    parseJSON (String "Situps")   = pure Situps
    parseJSON _ = mempty

instance Storable SetRep where
    timestamp = (^. srTime)


instance (HasTime obj, Storable obj) => HasTime (Sample obj) where
    time' = sData . time'


instance ToJSON obj => ToJSON (Sample obj) where
  toJSON (Sample id_ val) =
    object [ "id" .= id_
           , "data" .= val
           ]

instance FromJSON obj => FromJSON (Sample obj) where
  parseJSON (Object obj) =
    Sample <$> obj .: "id"
           <*> obj .: "data"
  parseJSON _ = mempty

