-- | Updateable objects
module Calamity.Internal.Updateable
    ( Updateable(..) ) where

import           Calamity.Internal.Utils
import           Calamity.Types.Model.Channel
import           Calamity.Types.Model.Channel.UpdatedMessage
import           Calamity.Types.Model.Guild.Guild
import           Calamity.Types.Model.User

import           Control.Lens

import           Data.Generics.Product.Fields
import           Data.Maybe

import           GHC.TypeLits

class Updateable a where
  type Updated a
  type Updated a = a

  update :: Updated a -> a -> a

-- | sets original field to new field
setF :: forall (f :: Symbol) o n b. (HasField' f o b, HasField' f o b, HasField' f n b) => n -> o -> o
setF :: n -> o -> o
setF n
n = forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f ((b -> Identity b) -> o -> Identity o) -> b -> o -> o
forall s t a b. ASetter s t a b -> b -> s -> t
.~ (n
n n -> Getting b n b -> b
forall s a. s -> Getting a s a -> a
^. forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f)

-- | sets original field to unwrapped new field if new field is not Nothing
mergeF :: forall (f :: Symbol) o n b. (HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) => o -> n -> o -> o
mergeF :: o -> n -> o -> o
mergeF o
o n
n = forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f ((b -> Identity b) -> o -> Identity o) -> b -> o -> o
forall s t a b. ASetter s t a b -> b -> s -> t
.~ b -> Maybe b -> b
forall a. a -> Maybe a -> a
fromMaybe (o
o o -> Getting b o b -> b
forall s a. s -> Getting a s a -> a
^. forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f) (n
n n -> Getting (Maybe b) n (Maybe b) -> Maybe b
forall s a. s -> Getting a s a -> a
^. forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f)

-- | sets original field to new field if new field is not Nothing
mergeF' :: forall (f :: Symbol) o n b. (HasField' f o (Maybe b), HasField' f n (Maybe b)) => o -> n -> o -> o
mergeF' :: o -> n -> o -> o
mergeF' o
o n
n = forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f ((Maybe b -> Identity (Maybe b)) -> o -> Identity o)
-> Maybe b -> o -> o
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe b -> Maybe b -> Maybe b
forall a. Maybe a -> Maybe a -> Maybe a
lastMaybe (o
o o -> Getting (Maybe b) o (Maybe b) -> Maybe b
forall s a. s -> Getting a s a -> a
^. forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f) (n
n n -> Getting (Maybe b) n (Maybe b) -> Maybe b
forall s a. s -> Getting a s a -> a
^. forall s a. HasField' f s a => Lens s s a a
forall (field :: Symbol) s a. HasField' field s a => Lens s s a a
field' @f)

instance Updateable Message where
  type Updated Message = UpdatedMessage

  update :: Updated Message -> Message -> Message
update Updated Message
n Message
o = Message
o
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"content" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"editedTimestamp" UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"tts" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"mentionEveryone" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"mentions" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"mentionRoles" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"mentionChannels" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"attachments" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"embeds" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"reactions" Message
o UpdatedMessage
Updated Message
n
    Message -> (Message -> Message) -> Message
forall a b. a -> (a -> b) -> b
& Message -> UpdatedMessage -> Message -> Message
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"pinned" Message
o UpdatedMessage
Updated Message
n

instance Updateable Channel where
  update :: Updated Channel -> Channel -> Channel
update Updated Channel
n Channel
_ = Channel
Updated Channel
n

instance Updateable DMChannel where
  update :: Updated DMChannel -> DMChannel -> DMChannel
update Updated DMChannel
n DMChannel
_ = DMChannel
Updated DMChannel
n

instance Updateable GuildChannel where
  update :: Updated GuildChannel -> GuildChannel -> GuildChannel
update Updated GuildChannel
n GuildChannel
_ = GuildChannel
Updated GuildChannel
n

instance Updateable Guild where
  type Updated Guild = UpdatedGuild

  -- For updating guild we just put in the non-present data from
  update :: Updated Guild -> Guild -> Guild
update Updated Guild
n Guild
o = Guild
o
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"name" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"icon" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"splash" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"owner" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"ownerID" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& Guild -> UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"permissions" Guild
o UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"region" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"afkChannelID" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"afkTimeout" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& Guild -> UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"embedEnabled" Guild
o UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"embedChannelID" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"verificationLevel" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"defaultMessageNotifications" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"explicitContentFilter" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"roles" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"features" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"mfaLevel" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"applicationID" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& Guild -> UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF @"widgetEnabled" Guild
o UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"widgetChannelID" UpdatedGuild
Updated Guild
n
    Guild -> (Guild -> Guild) -> Guild
forall a b. a -> (a -> b) -> b
& UpdatedGuild -> Guild -> Guild
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"systemChannelID" UpdatedGuild
Updated Guild
n

instance Updateable User where
  update :: Updated User -> User -> User
update Updated User
n User
o = User
o
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"username" User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o b, HasField' f o b, HasField' f n b) =>
n -> o -> o
setF @"discriminator" User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"bot" User
o User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"avatar" User
o User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"mfaEnabled" User
o User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"verified" User
o User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"email" User
o User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"flags" User
o User
Updated User
n
    User -> (User -> User) -> User
forall a b. a -> (a -> b) -> b
& User -> User -> User -> User
forall (f :: Symbol) o n b.
(HasField' f o (Maybe b), HasField' f n (Maybe b)) =>
o -> n -> o -> o
mergeF' @"premiumType" User
o User
Updated User
n