content: {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE StandaloneDeriving #-}
  {-# LANGUAGE TypeApplications #-}
  {-# OPTIONS_GHC -Wno-orphans #-}
  
  -- This file is part of the Wire Server implementation.
  --
  -- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
  --
  -- This program is free software: you can redistribute it and/or modify it under
  -- the terms of the GNU Affero General Public License as published by the Free
  -- Software Foundation, either version 3 of the License, or (at your option) any
  -- later version.
  --
  -- This program is distributed in the hope that it will be useful, but WITHOUT
  -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  -- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  -- details.
  --
  -- You should have received a copy of the GNU Affero General Public License along
  -- with this program. If not, see <https://www.gnu.org/licenses/>.
  
  module Types where
  
  import Cassandra
  import Data.Aeson (FromJSON (..), ToJSON (..), Value (String), withArray, withText)
  import Data.Aeson.Types (Value (Array))
  import Data.ByteString.Lazy (fromStrict, toStrict)
  import Data.IP (IP (..))
  import Data.Id
  import Data.Text qualified as T
  import Data.Text.Ascii (AsciiText, Base64, decodeBase64, encodeBase64)
  import Data.Vector qualified as V
  import Imports
  import System.Logger (Logger)
  import Wire.ConversationStore.Cassandra.Instances ()
  
  data Env = Env
    { envLogger :: Logger,
      envBrig :: ClientState,
      envGalley :: ClientState,
      envSpar :: ClientState,
      envGundeck :: ClientState,
      envTargetPath :: FilePath,
      envTeamId :: TeamId,
      envPageSize :: Int32
    }
  
  -- | (ideally, we shouldn't need this, since we shouldn't even touch tables that have this in them.)
  data AssetIgnoreData = AssetIgnoreData
  
  instance {-# OVERLAPPING #-} FromJSON [AssetIgnoreData] where
    parseJSON _ = pure []
  
  instance {-# OVERLAPPING #-} ToJSON [AssetIgnoreData] where
    toJSON _ = Array $ V.fromList []
  
  instance Cql AssetIgnoreData where
    ctype =
      Tagged
        ( UdtColumn
            "asset"
            [ ("typ", IntColumn),
              ("key", VarCharColumn),
              ("size", IntColumn) -- FUTUREWORK check if this works
            ]
        )
    toCql _ = error "AssetIgnoreData: you should not have any data of this"
    fromCql _ = pure AssetIgnoreData
  
  instance (ToJSON a) => ToJSON (Cassandra.Set a) where
    toJSON = toJSON . Cassandra.fromSet
  
  instance (FromJSON a) => FromJSON (Cassandra.Set a) where
    parseJSON = fmap Cassandra.Set . parseJSON
  
  instance ToJSON Blob where
    toJSON (Blob bstr) = toJSON (encodeBase64 (toStrict bstr))
  
  instance FromJSON Blob where
    parseJSON x = do
      y <- parseJSON @(AsciiText Base64) x
      case decodeBase64 y of
        Nothing -> fail "Blob': not a valid base64 string"
        Just bs -> pure . Blob . fromStrict $ bs
  
  instance ToJSON IP where
    toJSON ip = String (T.pack . show $ ip)
  
  instance FromJSON IP where
    parseJSON = withText "IP" $ \str ->
      case (read . T.unpack) str of
        Nothing -> fail "not a formatted IP address"
        Just ip -> pure ip
  
  deriving instance ToJSON Ascii
  
  deriving instance FromJSON Ascii
  
  deriving instance ToJSON TimeUuid
  
  deriving instance FromJSON TimeUuid
  
  instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i, ToJSON j, ToJSON k, ToJSON l, ToJSON m, ToJSON n, ToJSON o, ToJSON p, ToJSON q, ToJSON r, ToJSON s, ToJSON t) => ToJSON ((,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t) where
    toJSON (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) =
      Array $
        V.fromList
          [ toJSON a,
            toJSON b,
            toJSON c,
            toJSON d,
            toJSON e,
            toJSON f,
            toJSON g,
            toJSON h,
            toJSON i,
            toJSON j,
            toJSON k,
            toJSON l,
            toJSON m,
            toJSON n,
            toJSON o,
            toJSON p,
            toJSON q,
            toJSON r,
            toJSON s,
            toJSON t
          ]
  
  instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j, FromJSON k, FromJSON l, FromJSON m, FromJSON n, FromJSON o, FromJSON p, FromJSON q, FromJSON r, FromJSON s, FromJSON t) => FromJSON ((,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t) where
    parseJSON = withArray "Tuple" $ \case
      (toList -> [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t]) ->
        (,,,,,,,,,,,,,,,,,,,)
          <$> parseJSON a
          <*> parseJSON b
          <*> parseJSON c
          <*> parseJSON d
          <*> parseJSON e
          <*> parseJSON f
          <*> parseJSON g
          <*> parseJSON h
          <*> parseJSON i
          <*> parseJSON j
          <*> parseJSON k
          <*> parseJSON l
          <*> parseJSON m
          <*> parseJSON n
          <*> parseJSON o
          <*> parseJSON p
          <*> parseJSON q
          <*> parseJSON r
          <*> parseJSON s
          <*> parseJSON t
      _ -> fail "Expected array of length 21"
  