-- | 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 Data.Maybe
import GHC.TypeLits
import Optics

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 k.
  ( k ~ A_Lens
  , LabelOptic' f k o b
  , LabelOptic' f k n b
  ) =>
  n ->
  o ->
  o
setF :: forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF n
n = forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> b -> s -> t
.~ n
n forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f

-- | sets original field to unwrapped new field if new field is not Nothing
mergeF ::
  forall (f :: Symbol) o n b k.
  ( k ~ A_Lens
  , LabelOptic' f k o b
  , LabelOptic' f k n (Maybe b)
  ) =>
  n ->
  o ->
  o
mergeF :: forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF n
n = forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ \b
oldv -> forall a. a -> Maybe a -> a
fromMaybe b
oldv (n
n forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f)

-- | sets original field to new field if new field is not nothing
mergeF' ::
  forall (f :: Symbol) old new v k.
  ( k ~ A_Lens
  , LabelOptic' f k old (Maybe v)
  , LabelOptic' f k new (Maybe v)
  ) =>
  new ->
  old ->
  old
mergeF' :: forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe v)) =>
new -> old -> old
mergeF' new
new = forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ \Maybe v
oldv -> forall a. Maybe a -> Maybe a -> Maybe a
lastMaybe Maybe v
oldv (new
new forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f)

-- | sets original field to new field if new field was present
updateNullableDest ::
  forall (f :: Symbol) old new v k.
  ( k ~ A_Lens
  , LabelOptic' f k old (Maybe v)
  , LabelOptic' f k new (Maybe (MaybeNull v))
  ) =>
  new ->
  old ->
  old
updateNullableDest :: forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest new
new = case new
new forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f of
  Just (NotNull v
x) -> forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a (Maybe b) -> b -> s -> t
?~ v
x
  Just MaybeNull v
WasNull -> forall (name :: Symbol) k s t a b.
LabelOptic name k s t a b =>
Optic k NoIx s t a b
labelOptic @f forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> b -> s -> t
.~ forall a. Maybe a
Nothing
  Maybe (MaybeNull v)
Nothing -> forall a. a -> a
Prelude.id

-- NOTE: afaik only messages get partial updates
instance Updateable Message where
  type Updated Message = UpdatedMessage

  update :: Updated Message -> Message -> Message
update Updated Message
n Message
o =
    Message
o
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"content" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest @"editedTimestamp" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"tts" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"mentionEveryone" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"mentions" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"mentionRoles" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"mentionChannels" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"attachments" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"embeds" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"reactions" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"pinned" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"type_" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest @"activity" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest @"application" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest @"messageReference" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"flags" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest @"referencedMessage" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) old new v k.
(k ~ A_Lens, LabelOptic' f k old (Maybe v),
 LabelOptic' f k new (Maybe (MaybeNull v))) =>
new -> old -> old
updateNullableDest @"interaction" Updated Message
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"components" Updated Message
n

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

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

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

instance Updateable Guild where
  type Updated Guild = UpdatedGuild

  update :: Updated Guild -> Guild -> Guild
update Updated Guild
n Guild
o =
    Guild
o
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"name" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"icon" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"splash" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"discoverySplash" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"banner" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"owner" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"ownerID" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"permissions" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"afkChannelID" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"afkTimeout" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"embedEnabled" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"embedChannelID" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"verificationLevel" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"defaultMessageNotifications" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"explicitContentFilter" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"roles" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"features" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"mfaLevel" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"applicationID" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n (Maybe b)) =>
n -> o -> o
mergeF @"widgetEnabled" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"widgetChannelID" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"systemChannelID" Updated Guild
n
      forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) o n b k.
(k ~ A_Lens, LabelOptic' f k o b, LabelOptic' f k n b) =>
n -> o -> o
setF @"preferredLocale" Updated Guild
n

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