{-# LANGUAGE RecordWildCards #-}

-- 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 Schema where

import Cassandra
import Common
import Data.Conduit
import Data.IP (IP)
import Data.Id
import Data.Time
import Data.UUID
import Imports
import System.FilePath.Posix ((</>))
import Types
import Wire.API.Team.Permission
import Wire.ConversationStore.Cassandra.Instances ()

-- This file was autogenerated by move-team-generate

-- brig.clients

type RowBrigClients = (Maybe UUID, Maybe Text, Maybe Int32, Maybe Text, Maybe IP, Maybe Text, Maybe Double, Maybe Double, Maybe Text, Maybe UTCTime, Maybe Int32)

selectBrigClients :: PrepQuery R (Identity [UserId]) RowBrigClients
selectBrigClients = "SELECT user, client, class, cookie, ip, label, lat, lon, model, tstamp, type FROM clients WHERE user in ?"

readBrigClients :: Env -> [UserId] -> ConduitM () [RowBrigClients] IO ()
readBrigClients Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigClients (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigClientsAll :: PrepQuery R () RowBrigClients
selectBrigClientsAll = "SELECT user, client, class, cookie, ip, label, lat, lon, model, tstamp, type FROM clients"

readBrigClientsAll :: Env -> ConduitM () [RowBrigClients] IO ()
readBrigClientsAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigClientsAll (paramsP LocalQuorum () envPageSize) x5

exportBrigClientsFull :: Env -> FilePath -> IO ()
exportBrigClientsFull env path = do
  putStrLn $ "Exporting " <> "brig.clients" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigClientsAll env
        .| sinkJsonLines handle

insertBrigClients :: PrepQuery W RowBrigClients ()
insertBrigClients =
  "INSERT INTO clients (user, client, class, cookie, ip, label, lat, lon, model, tstamp, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

importBrigClients :: Env -> FilePath -> IO ()
importBrigClients Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.clients"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigClients)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.connection

type RowBrigConnection = (Maybe UUID, Maybe UUID, Maybe UUID, Maybe UTCTime, Maybe Text, Maybe Int32)

selectBrigConnection :: PrepQuery R (Identity [UserId]) RowBrigConnection
selectBrigConnection = "SELECT left, right, conv, last_update, message, status FROM connection WHERE left in ?"

readBrigConnection :: Env -> [UserId] -> ConduitM () [RowBrigConnection] IO ()
readBrigConnection Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigConnection (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigConnectionAll :: PrepQuery R () RowBrigConnection
selectBrigConnectionAll = "SELECT left, right, conv, last_update, message, status FROM connection"

readBrigConnectionAll :: Env -> ConduitM () [RowBrigConnection] IO ()
readBrigConnectionAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigConnectionAll (paramsP LocalQuorum () envPageSize) x5

exportBrigConnectionFull :: Env -> FilePath -> IO ()
exportBrigConnectionFull env path = do
  putStrLn $ "Exporting " <> "brig.connection" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigConnectionAll env
        .| sinkJsonLines handle

insertBrigConnection :: PrepQuery W RowBrigConnection ()
insertBrigConnection =
  "INSERT INTO connection (left, right, conv, last_update, message, status) VALUES (?, ?, ?, ?, ?, ?)"

importBrigConnection :: Env -> FilePath -> IO ()
importBrigConnection Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.connection"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigConnection)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.login_codes

type RowBrigLoginCodes = (Maybe UUID, Maybe Text, Maybe Int32, Maybe UTCTime)

selectBrigLoginCodes :: PrepQuery R (Identity [UserId]) RowBrigLoginCodes
selectBrigLoginCodes = "SELECT user, code, retries, timeout FROM login_codes WHERE user in ?"

readBrigLoginCodes :: Env -> [UserId] -> ConduitM () [RowBrigLoginCodes] IO ()
readBrigLoginCodes Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigLoginCodes (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigLoginCodesAll :: PrepQuery R () RowBrigLoginCodes
selectBrigLoginCodesAll = "SELECT user, code, retries, timeout FROM login_codes"

readBrigLoginCodesAll :: Env -> ConduitM () [RowBrigLoginCodes] IO ()
readBrigLoginCodesAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigLoginCodesAll (paramsP LocalQuorum () envPageSize) x5

exportBrigLoginCodesFull :: Env -> FilePath -> IO ()
exportBrigLoginCodesFull env path = do
  putStrLn $ "Exporting " <> "brig.login_codes" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigLoginCodesAll env
        .| sinkJsonLines handle

insertBrigLoginCodes :: PrepQuery W RowBrigLoginCodes ()
insertBrigLoginCodes =
  "INSERT INTO login_codes (user, code, retries, timeout) VALUES (?, ?, ?, ?)"

importBrigLoginCodes :: Env -> FilePath -> IO ()
importBrigLoginCodes Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.login_codes"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigLoginCodes)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.password_reset

type RowBrigPasswordReset = (Maybe Ascii, Maybe Ascii, Maybe Int32, Maybe UTCTime, Maybe UUID)

selectBrigPasswordResetAll :: PrepQuery R () RowBrigPasswordReset
selectBrigPasswordResetAll = "SELECT key, code, retries, timeout, user FROM password_reset"

readBrigPasswordResetAll :: Env -> ConduitM () [RowBrigPasswordReset] IO ()
readBrigPasswordResetAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigPasswordResetAll (paramsP LocalQuorum () envPageSize) x5

exportBrigPasswordResetFull :: Env -> FilePath -> IO ()
exportBrigPasswordResetFull env path = do
  putStrLn $ "Exporting " <> "brig.password_reset" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigPasswordResetAll env
        .| sinkJsonLines handle

insertBrigPasswordReset :: PrepQuery W RowBrigPasswordReset ()
insertBrigPasswordReset =
  "INSERT INTO password_reset (key, code, retries, timeout, user) VALUES (?, ?, ?, ?, ?)"

importBrigPasswordReset :: Env -> FilePath -> IO ()
importBrigPasswordReset Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.password_reset"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigPasswordReset)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.prekeys

type RowBrigPrekeys = (Maybe UUID, Maybe Text, Maybe Int32, Maybe Text)

selectBrigPrekeys :: PrepQuery R (Identity [UserId]) RowBrigPrekeys
selectBrigPrekeys = "SELECT user, client, key, data FROM prekeys WHERE user in ?"

readBrigPrekeys :: Env -> [UserId] -> ConduitM () [RowBrigPrekeys] IO ()
readBrigPrekeys Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigPrekeys (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigPrekeysAll :: PrepQuery R () RowBrigPrekeys
selectBrigPrekeysAll = "SELECT user, client, key, data FROM prekeys"

readBrigPrekeysAll :: Env -> ConduitM () [RowBrigPrekeys] IO ()
readBrigPrekeysAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigPrekeysAll (paramsP LocalQuorum () envPageSize) x5

exportBrigPrekeysFull :: Env -> FilePath -> IO ()
exportBrigPrekeysFull env path = do
  putStrLn $ "Exporting " <> "brig.prekeys" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigPrekeysAll env
        .| sinkJsonLines handle

insertBrigPrekeys :: PrepQuery W RowBrigPrekeys ()
insertBrigPrekeys =
  "INSERT INTO prekeys (user, client, key, data) VALUES (?, ?, ?, ?)"

importBrigPrekeys :: Env -> FilePath -> IO ()
importBrigPrekeys Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.prekeys"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigPrekeys)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.properties

type RowBrigProperties = (Maybe UUID, Maybe Ascii, Maybe Blob)

selectBrigProperties :: PrepQuery R (Identity [UserId]) RowBrigProperties
selectBrigProperties = "SELECT user, key, value FROM properties WHERE user in ?"

readBrigProperties :: Env -> [UserId] -> ConduitM () [RowBrigProperties] IO ()
readBrigProperties Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigProperties (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigPropertiesAll :: PrepQuery R () RowBrigProperties
selectBrigPropertiesAll = "SELECT user, key, value FROM properties"

readBrigPropertiesAll :: Env -> ConduitM () [RowBrigProperties] IO ()
readBrigPropertiesAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigPropertiesAll (paramsP LocalQuorum () envPageSize) x5

exportBrigPropertiesFull :: Env -> FilePath -> IO ()
exportBrigPropertiesFull env path = do
  putStrLn $ "Exporting " <> "brig.properties" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigPropertiesAll env
        .| sinkJsonLines handle

insertBrigProperties :: PrepQuery W RowBrigProperties ()
insertBrigProperties =
  "INSERT INTO properties (user, key, value) VALUES (?, ?, ?)"

importBrigProperties :: Env -> FilePath -> IO ()
importBrigProperties Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.properties"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigProperties)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.rich_info

type RowBrigRichInfo = (Maybe UUID, Maybe Blob)

selectBrigRichInfo :: PrepQuery R (Identity [UserId]) RowBrigRichInfo
selectBrigRichInfo = "SELECT user, json FROM rich_info WHERE user in ?"

readBrigRichInfo :: Env -> [UserId] -> ConduitM () [RowBrigRichInfo] IO ()
readBrigRichInfo Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigRichInfo (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigRichInfoAll :: PrepQuery R () RowBrigRichInfo
selectBrigRichInfoAll = "SELECT user, json FROM rich_info"

readBrigRichInfoAll :: Env -> ConduitM () [RowBrigRichInfo] IO ()
readBrigRichInfoAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigRichInfoAll (paramsP LocalQuorum () envPageSize) x5

exportBrigRichInfoFull :: Env -> FilePath -> IO ()
exportBrigRichInfoFull env path = do
  putStrLn $ "Exporting " <> "brig.rich_info" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigRichInfoAll env
        .| sinkJsonLines handle

insertBrigRichInfo :: PrepQuery W RowBrigRichInfo ()
insertBrigRichInfo =
  "INSERT INTO rich_info (user, json) VALUES (?, ?)"

importBrigRichInfo :: Env -> FilePath -> IO ()
importBrigRichInfo Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.rich_info"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigRichInfo)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.user

type RowBrigUser = (Maybe UUID, Maybe [Float], Maybe Int32, Maybe Bool, Maybe [AssetIgnoreData], Maybe Ascii, Maybe Text, Maybe UTCTime, Maybe Text, Maybe Ascii, Maybe Int32, Maybe Text, Maybe Blob, Maybe [Blob], Maybe UUID, Maybe Bool, Maybe UUID, Maybe Text, Maybe Int32, Maybe UUID)

selectBrigUser :: PrepQuery R (Identity [UserId]) RowBrigUser
selectBrigUser = "SELECT id, accent, accent_id, activated, assets, country, email, expires, handle, language, managed_by, name, password, picture, provider, searchable, service, sso_id, status, team FROM user WHERE id in ?"

readBrigUser :: Env -> [UserId] -> ConduitM () [RowBrigUser] IO ()
readBrigUser Env {..} uids =
  transPipe (runClient envBrig) $
    paginateC selectBrigUser (paramsP LocalQuorum (pure uids) envPageSize) x5

selectBrigUserAll :: PrepQuery R () RowBrigUser
selectBrigUserAll = "SELECT id, accent, accent_id, activated, assets, country, email, expires, handle, language, managed_by, name, password, picture, provider, searchable, service, sso_id, status, team FROM user"

readBrigUserAll :: Env -> ConduitM () [RowBrigUser] IO ()
readBrigUserAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigUserAll (paramsP LocalQuorum () envPageSize) x5

exportBrigUserFull :: Env -> FilePath -> IO ()
exportBrigUserFull env path = do
  putStrLn $ "Exporting " <> "brig.user" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigUserAll env
        .| sinkJsonLines handle

insertBrigUser :: PrepQuery W RowBrigUser ()
insertBrigUser =
  "INSERT INTO user (id, accent, accent_id, activated, assets, country, email, expires, handle, language, managed_by, name, password, picture, provider, searchable, service, sso_id, status, team) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

importBrigUser :: Env -> FilePath -> IO ()
importBrigUser Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.user"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigUser)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.user_handle

type RowBrigUserHandle = (Maybe Text, Maybe UUID)

selectBrigUserHandleAll :: PrepQuery R () RowBrigUserHandle
selectBrigUserHandleAll = "SELECT handle, user FROM user_handle"

readBrigUserHandleAll :: Env -> ConduitM () [RowBrigUserHandle] IO ()
readBrigUserHandleAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigUserHandleAll (paramsP LocalQuorum () envPageSize) x5

exportBrigUserHandleFull :: Env -> FilePath -> IO ()
exportBrigUserHandleFull env path = do
  putStrLn $ "Exporting " <> "brig.user_handle" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigUserHandleAll env
        .| sinkJsonLines handle

insertBrigUserHandle :: PrepQuery W RowBrigUserHandle ()
insertBrigUserHandle =
  "INSERT INTO user_handle (handle, user) VALUES (?, ?)"

importBrigUserHandle :: Env -> FilePath -> IO ()
importBrigUserHandle Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.user_handle"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigUserHandle)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- brig.user_keys

type RowBrigUserKeys = (Maybe Text, Maybe UUID)

selectBrigUserKeysAll :: PrepQuery R () RowBrigUserKeys
selectBrigUserKeysAll = "SELECT key, user FROM user_keys"

readBrigUserKeysAll :: Env -> ConduitM () [RowBrigUserKeys] IO ()
readBrigUserKeysAll Env {..} =
  transPipe (runClient envBrig) $
    paginateC selectBrigUserKeysAll (paramsP LocalQuorum () envPageSize) x5

exportBrigUserKeysFull :: Env -> FilePath -> IO ()
exportBrigUserKeysFull env path = do
  putStrLn $ "Exporting " <> "brig.user_keys" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readBrigUserKeysAll env
        .| sinkJsonLines handle

insertBrigUserKeys :: PrepQuery W RowBrigUserKeys ()
insertBrigUserKeys =
  "INSERT INTO user_keys (key, user) VALUES (?, ?)"

importBrigUserKeys :: Env -> FilePath -> IO ()
importBrigUserKeys Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "brig.user_keys"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envBrig) (sinkTableRows insertBrigUserKeys)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.billing_team_member

type RowGalleyBillingTeamMember = (Maybe UUID, Maybe UUID)

selectGalleyBillingTeamMember :: PrepQuery R (Identity TeamId) RowGalleyBillingTeamMember
selectGalleyBillingTeamMember = "SELECT team, user FROM billing_team_member WHERE team = ?"

readGalleyBillingTeamMember :: Env -> TeamId -> ConduitM () [RowGalleyBillingTeamMember] IO ()
readGalleyBillingTeamMember Env {..} tid =
  transPipe (runClient envGalley) $
    paginateC selectGalleyBillingTeamMember (paramsP LocalQuorum (pure tid) envPageSize) x5

selectGalleyBillingTeamMemberAll :: PrepQuery R () RowGalleyBillingTeamMember
selectGalleyBillingTeamMemberAll = "SELECT team, user FROM billing_team_member"

readGalleyBillingTeamMemberAll :: Env -> ConduitM () [RowGalleyBillingTeamMember] IO ()
readGalleyBillingTeamMemberAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyBillingTeamMemberAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyBillingTeamMemberFull :: Env -> FilePath -> IO ()
exportGalleyBillingTeamMemberFull env path = do
  putStrLn $ "Exporting " <> "galley.billing_team_member" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyBillingTeamMemberAll env
        .| sinkJsonLines handle

insertGalleyBillingTeamMember :: PrepQuery W RowGalleyBillingTeamMember ()
insertGalleyBillingTeamMember =
  "INSERT INTO billing_team_member (team, user) VALUES (?, ?)"

importGalleyBillingTeamMember :: Env -> FilePath -> IO ()
importGalleyBillingTeamMember Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.billing_team_member"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyBillingTeamMember)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.clients

type RowGalleyClients = (Maybe UUID, Maybe (Cassandra.Set Text))

selectGalleyClients :: PrepQuery R (Identity [UserId]) RowGalleyClients
selectGalleyClients = "SELECT user, clients FROM clients WHERE user in ?"

readGalleyClients :: Env -> [UserId] -> ConduitM () [RowGalleyClients] IO ()
readGalleyClients Env {..} uids =
  transPipe (runClient envGalley) $
    paginateC selectGalleyClients (paramsP LocalQuorum (pure uids) envPageSize) x5

selectGalleyClientsAll :: PrepQuery R () RowGalleyClients
selectGalleyClientsAll = "SELECT user, clients FROM clients"

readGalleyClientsAll :: Env -> ConduitM () [RowGalleyClients] IO ()
readGalleyClientsAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyClientsAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyClientsFull :: Env -> FilePath -> IO ()
exportGalleyClientsFull env path = do
  putStrLn $ "Exporting " <> "galley.clients" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyClientsAll env
        .| sinkJsonLines handle

insertGalleyClients :: PrepQuery W RowGalleyClients ()
insertGalleyClients =
  "INSERT INTO clients (user, clients) VALUES (?, ?)"

importGalleyClients :: Env -> FilePath -> IO ()
importGalleyClients Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.clients"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyClients)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.conversation

type RowGalleyConversation =
  ( Maybe UUID,
    Maybe (Cassandra.Set Int32),
    Maybe Int32,
    Maybe UUID,
    Maybe Bool,
    Maybe Int64,
    Maybe Text,
    Maybe Int32,
    Maybe UUID,
    Maybe Int32,
    Maybe UUID
  )

selectGalleyConversation :: PrepQuery R (Identity [ConvId]) RowGalleyConversation
selectGalleyConversation = "SELECT conv, access, access_role, creator, deleted, message_timer, name, receipt_mode, team, type, parent_conv FROM conversation WHERE conv in ?"

readGalleyConversation :: Env -> [ConvId] -> ConduitM () [RowGalleyConversation] IO ()
readGalleyConversation Env {..} cids =
  transPipe (runClient envGalley) $
    paginateC selectGalleyConversation (paramsP LocalQuorum (pure cids) envPageSize) x5

selectGalleyConversationAll :: PrepQuery R () RowGalleyConversation
selectGalleyConversationAll = "SELECT conv, access, access_role, creator, deleted, message_timer, name, receipt_mode, team, type, parent_conv FROM conversation"

readGalleyConversationAll :: Env -> ConduitM () [RowGalleyConversation] IO ()
readGalleyConversationAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyConversationAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyConversationFull :: Env -> FilePath -> IO ()
exportGalleyConversationFull env path = do
  putStrLn $ "Exporting " <> "galley.conversation" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyConversationAll env
        .| sinkJsonLines handle

insertGalleyConversation :: PrepQuery W RowGalleyConversation ()
insertGalleyConversation =
  "INSERT INTO conversation (conv, access, access_role, creator, deleted, message_timer, name, receipt_mode, team, type, parent_conv) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

importGalleyConversation :: Env -> FilePath -> IO ()
importGalleyConversation Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.conversation"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyConversation)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.member

type RowGalleyMember = (Maybe UUID, Maybe UUID, Maybe Text, Maybe Bool, Maybe Text, Maybe Bool, Maybe Text, Maybe Bool, Maybe Text, Maybe Int32, Maybe UUID, Maybe UUID, Maybe Int32, Maybe Text, Maybe UUID)

selectGalleyMember :: PrepQuery R (Identity [ConvId]) RowGalleyMember
selectGalleyMember = "SELECT conv, user, conversation_role, hidden, hidden_ref, otr_archived, otr_archived_ref, otr_muted, otr_muted_ref, otr_muted_status, provider, service, status, user_remote_domain, user_remote_id FROM member WHERE conv in ?"

readGalleyMember :: Env -> [ConvId] -> ConduitM () [RowGalleyMember] IO ()
readGalleyMember Env {..} cids =
  transPipe (runClient envGalley) $
    paginateC selectGalleyMember (paramsP LocalQuorum (pure cids) envPageSize) x5

selectGalleyMemberAll :: PrepQuery R () RowGalleyMember
selectGalleyMemberAll = "SELECT conv, user, conversation_role, hidden, hidden_ref, otr_archived, otr_archived_ref, otr_muted, otr_muted_ref, otr_muted_status, provider, service, status, user_remote_domain, user_remote_id FROM member"

readGalleyMemberAll :: Env -> ConduitM () [RowGalleyMember] IO ()
readGalleyMemberAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyMemberAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyMemberFull :: Env -> FilePath -> IO ()
exportGalleyMemberFull env path = do
  putStrLn $ "Exporting " <> "galley.member" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyMemberAll env
        .| sinkJsonLines handle

insertGalleyMember :: PrepQuery W RowGalleyMember ()
insertGalleyMember =
  "INSERT INTO member (conv, user, conversation_role, hidden, hidden_ref, otr_archived, otr_archived_ref, otr_muted, otr_muted_ref, otr_muted_status, provider, service, status, user_remote_domain, user_remote_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

importGalleyMember :: Env -> FilePath -> IO ()
importGalleyMember Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.member"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyMember)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.team

type RowGalleyTeam = (Maybe UUID, Maybe Bool, Maybe UUID, Maybe Bool, Maybe Text, Maybe Text, Maybe Text, Maybe Int32, Maybe Int32)

selectGalleyTeam :: PrepQuery R (Identity TeamId) RowGalleyTeam
selectGalleyTeam = "SELECT team, binding, creator, deleted, icon, icon_key, name, search_visibility, status FROM team WHERE team = ?"

readGalleyTeam :: Env -> TeamId -> ConduitM () [RowGalleyTeam] IO ()
readGalleyTeam Env {..} tid =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeam (paramsP LocalQuorum (pure tid) envPageSize) x5

selectGalleyTeamAll :: PrepQuery R () RowGalleyTeam
selectGalleyTeamAll = "SELECT team, binding, creator, deleted, icon, icon_key, name, search_visibility, status FROM team"

readGalleyTeamAll :: Env -> ConduitM () [RowGalleyTeam] IO ()
readGalleyTeamAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyTeamFull :: Env -> FilePath -> IO ()
exportGalleyTeamFull env path = do
  putStrLn $ "Exporting " <> "galley.team" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyTeamAll env
        .| sinkJsonLines handle

insertGalleyTeam :: PrepQuery W RowGalleyTeam ()
insertGalleyTeam =
  "INSERT INTO team (team, binding, creator, deleted, icon, icon_key, name, search_visibility, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"

importGalleyTeam :: Env -> FilePath -> IO ()
importGalleyTeam Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.team"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyTeam)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.team_conv

type RowGalleyTeamConv = (Maybe UUID, Maybe UUID, Maybe Bool)

selectGalleyTeamConv :: PrepQuery R (Identity TeamId) RowGalleyTeamConv
selectGalleyTeamConv = "SELECT team, conv, managed FROM team_conv WHERE team = ?"

readGalleyTeamConv :: Env -> TeamId -> ConduitM () [RowGalleyTeamConv] IO ()
readGalleyTeamConv Env {..} tid =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamConv (paramsP LocalQuorum (pure tid) envPageSize) x5

selectGalleyTeamConvAll :: PrepQuery R () RowGalleyTeamConv
selectGalleyTeamConvAll = "SELECT team, conv, managed FROM team_conv"

readGalleyTeamConvAll :: Env -> ConduitM () [RowGalleyTeamConv] IO ()
readGalleyTeamConvAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamConvAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyTeamConvFull :: Env -> FilePath -> IO ()
exportGalleyTeamConvFull env path = do
  putStrLn $ "Exporting " <> "galley.team_conv" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyTeamConvAll env
        .| sinkJsonLines handle

insertGalleyTeamConv :: PrepQuery W RowGalleyTeamConv ()
insertGalleyTeamConv =
  "INSERT INTO team_conv (team, conv, managed) VALUES (?, ?, ?)"

importGalleyTeamConv :: Env -> FilePath -> IO ()
importGalleyTeamConv Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.team_conv"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyTeamConv)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.team_features

type RowGalleyTeamFeatures = (Maybe UUID, Maybe Int32, Maybe Int32, Maybe Int32, Maybe Int32, Maybe Int32, Maybe Int32, Maybe Int32, Maybe Int32)

selectGalleyTeamFeatures :: PrepQuery R (Identity TeamId) RowGalleyTeamFeatures
selectGalleyTeamFeatures = "SELECT team_id, app_lock_enforce, app_lock_inactivity_timeout_secs, app_lock_status, digital_signatures, legalhold_status, search_visibility_status, sso_status, validate_saml_emails FROM team_features WHERE team_id = ?"

readGalleyTeamFeatures :: Env -> TeamId -> ConduitM () [RowGalleyTeamFeatures] IO ()
readGalleyTeamFeatures Env {..} tid =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamFeatures (paramsP LocalQuorum (pure tid) envPageSize) x5

selectGalleyTeamFeaturesAll :: PrepQuery R () RowGalleyTeamFeatures
selectGalleyTeamFeaturesAll = "SELECT team_id, app_lock_enforce, app_lock_inactivity_timeout_secs, app_lock_status, digital_signatures, legalhold_status, search_visibility_status, sso_status, validate_saml_emails FROM team_features"

readGalleyTeamFeaturesAll :: Env -> ConduitM () [RowGalleyTeamFeatures] IO ()
readGalleyTeamFeaturesAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamFeaturesAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyTeamFeaturesFull :: Env -> FilePath -> IO ()
exportGalleyTeamFeaturesFull env path = do
  putStrLn $ "Exporting " <> "galley.team_features" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyTeamFeaturesAll env
        .| sinkJsonLines handle

insertGalleyTeamFeatures :: PrepQuery W RowGalleyTeamFeatures ()
insertGalleyTeamFeatures =
  "INSERT INTO team_features (team_id, app_lock_enforce, app_lock_inactivity_timeout_secs, app_lock_status, digital_signatures, legalhold_status, search_visibility_status, sso_status, validate_saml_emails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"

importGalleyTeamFeatures :: Env -> FilePath -> IO ()
importGalleyTeamFeatures Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.team_features"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyTeamFeatures)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.team_member

type RowGalleyTeamMember = (Maybe UUID, Maybe UUID, Maybe UTCTime, Maybe UUID, Maybe Int32, Maybe Permissions)

selectGalleyTeamMember :: PrepQuery R (Identity TeamId) RowGalleyTeamMember
selectGalleyTeamMember = "SELECT team, user, invited_at, invited_by, legalhold_status, perms FROM team_member WHERE team = ?"

readGalleyTeamMember :: Env -> TeamId -> ConduitM () [RowGalleyTeamMember] IO ()
readGalleyTeamMember Env {..} tid =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamMember (paramsP LocalQuorum (pure tid) envPageSize) x5

selectGalleyTeamMemberAll :: PrepQuery R () RowGalleyTeamMember
selectGalleyTeamMemberAll = "SELECT team, user, invited_at, invited_by, legalhold_status, perms FROM team_member"

readGalleyTeamMemberAll :: Env -> ConduitM () [RowGalleyTeamMember] IO ()
readGalleyTeamMemberAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamMemberAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyTeamMemberFull :: Env -> FilePath -> IO ()
exportGalleyTeamMemberFull env path = do
  putStrLn $ "Exporting " <> "galley.team_member" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyTeamMemberAll env
        .| sinkJsonLines handle

insertGalleyTeamMember :: PrepQuery W RowGalleyTeamMember ()
insertGalleyTeamMember =
  "INSERT INTO team_member (team, user, invited_at, invited_by, legalhold_status, perms) VALUES (?, ?, ?, ?, ?, ?)"

importGalleyTeamMember :: Env -> FilePath -> IO ()
importGalleyTeamMember Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.team_member"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyTeamMember)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.team_notifications

type RowGalleyTeamNotifications = (Maybe UUID, Maybe TimeUuid, Maybe Blob)

selectGalleyTeamNotifications :: PrepQuery R (Identity TeamId) RowGalleyTeamNotifications
selectGalleyTeamNotifications = "SELECT team, id, payload FROM team_notifications WHERE team = ?"

readGalleyTeamNotifications :: Env -> TeamId -> ConduitM () [RowGalleyTeamNotifications] IO ()
readGalleyTeamNotifications Env {..} tid =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamNotifications (paramsP LocalQuorum (pure tid) envPageSize) x5

selectGalleyTeamNotificationsAll :: PrepQuery R () RowGalleyTeamNotifications
selectGalleyTeamNotificationsAll = "SELECT team, id, payload FROM team_notifications"

readGalleyTeamNotificationsAll :: Env -> ConduitM () [RowGalleyTeamNotifications] IO ()
readGalleyTeamNotificationsAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyTeamNotificationsAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyTeamNotificationsFull :: Env -> FilePath -> IO ()
exportGalleyTeamNotificationsFull env path = do
  putStrLn $ "Exporting " <> "galley.team_notifications" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyTeamNotificationsAll env
        .| sinkJsonLines handle

insertGalleyTeamNotifications :: PrepQuery W RowGalleyTeamNotifications ()
insertGalleyTeamNotifications =
  "INSERT INTO team_notifications (team, id, payload) VALUES (?, ?, ?)"

importGalleyTeamNotifications :: Env -> FilePath -> IO ()
importGalleyTeamNotifications Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.team_notifications"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyTeamNotifications)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.user

type RowGalleyUser = (Maybe UUID, Maybe UUID, Maybe Text, Maybe UUID)

selectGalleyUser :: PrepQuery R (Identity [UserId]) RowGalleyUser
selectGalleyUser = "SELECT user, conv, conv_remote_domain, conv_remote_id FROM user WHERE user in ?"

readGalleyUser :: Env -> [UserId] -> ConduitM () [RowGalleyUser] IO ()
readGalleyUser Env {..} uids =
  transPipe (runClient envGalley) $
    paginateC selectGalleyUser (paramsP LocalQuorum (pure uids) envPageSize) x5

selectGalleyUserAll :: PrepQuery R () RowGalleyUser
selectGalleyUserAll = "SELECT user, conv, conv_remote_domain, conv_remote_id FROM user"

readGalleyUserAll :: Env -> ConduitM () [RowGalleyUser] IO ()
readGalleyUserAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyUserAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyUserFull :: Env -> FilePath -> IO ()
exportGalleyUserFull env path = do
  putStrLn $ "Exporting " <> "galley.user" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyUserAll env
        .| sinkJsonLines handle

insertGalleyUser :: PrepQuery W RowGalleyUser ()
insertGalleyUser =
  "INSERT INTO user (user, conv, conv_remote_domain, conv_remote_id) VALUES (?, ?, ?, ?)"

importGalleyUser :: Env -> FilePath -> IO ()
importGalleyUser Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.user"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyUser)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- galley.user_team

type RowGalleyUserTeam = (Maybe UUID, Maybe UUID)

selectGalleyUserTeam :: PrepQuery R (Identity [UserId]) RowGalleyUserTeam
selectGalleyUserTeam = "SELECT user, team FROM user_team WHERE user in ?"

readGalleyUserTeam :: Env -> [UserId] -> ConduitM () [RowGalleyUserTeam] IO ()
readGalleyUserTeam Env {..} uids =
  transPipe (runClient envGalley) $
    paginateC selectGalleyUserTeam (paramsP LocalQuorum (pure uids) envPageSize) x5

selectGalleyUserTeamAll :: PrepQuery R () RowGalleyUserTeam
selectGalleyUserTeamAll = "SELECT user, team FROM user_team"

readGalleyUserTeamAll :: Env -> ConduitM () [RowGalleyUserTeam] IO ()
readGalleyUserTeamAll Env {..} =
  transPipe (runClient envGalley) $
    paginateC selectGalleyUserTeamAll (paramsP LocalQuorum () envPageSize) x5

exportGalleyUserTeamFull :: Env -> FilePath -> IO ()
exportGalleyUserTeamFull env path = do
  putStrLn $ "Exporting " <> "galley.user_team" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGalleyUserTeamAll env
        .| sinkJsonLines handle

insertGalleyUserTeam :: PrepQuery W RowGalleyUserTeam ()
insertGalleyUserTeam =
  "INSERT INTO user_team (user, team) VALUES (?, ?)"

importGalleyUserTeam :: Env -> FilePath -> IO ()
importGalleyUserTeam Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "galley.user_team"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGalley) (sinkTableRows insertGalleyUserTeam)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- gundeck.notifications

type RowGundeckNotifications = (Maybe UUID, Maybe TimeUuid, Maybe (Cassandra.Set Text), Maybe Blob)

selectGundeckNotifications :: PrepQuery R (Identity [UserId]) RowGundeckNotifications
selectGundeckNotifications = "SELECT user, id, clients, payload FROM notifications WHERE user in ?"

readGundeckNotifications :: Env -> [UserId] -> ConduitM () [RowGundeckNotifications] IO ()
readGundeckNotifications Env {..} uids =
  transPipe (runClient envGundeck) $
    paginateC selectGundeckNotifications (paramsP LocalQuorum (pure uids) envPageSize) x5

selectGundeckNotificationsAll :: PrepQuery R () RowGundeckNotifications
selectGundeckNotificationsAll = "SELECT user, id, clients, payload FROM notifications"

readGundeckNotificationsAll :: Env -> ConduitM () [RowGundeckNotifications] IO ()
readGundeckNotificationsAll Env {..} =
  transPipe (runClient envGundeck) $
    paginateC selectGundeckNotificationsAll (paramsP LocalQuorum () envPageSize) x5

exportGundeckNotificationsFull :: Env -> FilePath -> IO ()
exportGundeckNotificationsFull env path = do
  putStrLn $ "Exporting " <> "gundeck.notifications" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readGundeckNotificationsAll env
        .| sinkJsonLines handle

insertGundeckNotifications :: PrepQuery W RowGundeckNotifications ()
insertGundeckNotifications =
  "INSERT INTO notifications (user, id, clients, payload) VALUES (?, ?, ?, ?)"

importGundeckNotifications :: Env -> FilePath -> IO ()
importGundeckNotifications Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "gundeck.notifications"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envGundeck) (sinkTableRows insertGundeckNotifications)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- spar.scim_external

type RowSparScimExternal = (Maybe UUID, Maybe Text, Maybe UUID)

selectSparScimExternal :: PrepQuery R (Identity TeamId) RowSparScimExternal
selectSparScimExternal = "SELECT team, external_id, user FROM scim_external WHERE team = ?"

readSparScimExternal :: Env -> TeamId -> ConduitM () [RowSparScimExternal] IO ()
readSparScimExternal Env {..} tid =
  transPipe (runClient envSpar) $
    paginateC selectSparScimExternal (paramsP LocalQuorum (pure tid) envPageSize) x5

selectSparScimExternalAll :: PrepQuery R () RowSparScimExternal
selectSparScimExternalAll = "SELECT team, external_id, user FROM scim_external"

readSparScimExternalAll :: Env -> ConduitM () [RowSparScimExternal] IO ()
readSparScimExternalAll Env {..} =
  transPipe (runClient envSpar) $
    paginateC selectSparScimExternalAll (paramsP LocalQuorum () envPageSize) x5

exportSparScimExternalFull :: Env -> FilePath -> IO ()
exportSparScimExternalFull env path = do
  putStrLn $ "Exporting " <> "spar.scim_external" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readSparScimExternalAll env
        .| sinkJsonLines handle

insertSparScimExternal :: PrepQuery W RowSparScimExternal ()
insertSparScimExternal =
  "INSERT INTO scim_external (team, external_id, user) VALUES (?, ?, ?)"

importSparScimExternal :: Env -> FilePath -> IO ()
importSparScimExternal Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "spar.scim_external"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envSpar) (sinkTableRows insertSparScimExternal)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- spar.scim_user_times

type RowSparScimUserTimes = (Maybe UUID, Maybe UTCTime, Maybe UTCTime)

selectSparScimUserTimes :: PrepQuery R (Identity [UserId]) RowSparScimUserTimes
selectSparScimUserTimes = "SELECT uid, created_at, last_updated_at FROM scim_user_times WHERE uid in ?"

readSparScimUserTimes :: Env -> [UserId] -> ConduitM () [RowSparScimUserTimes] IO ()
readSparScimUserTimes Env {..} uids =
  transPipe (runClient envSpar) $
    paginateC selectSparScimUserTimes (paramsP LocalQuorum (pure uids) envPageSize) x5

selectSparScimUserTimesAll :: PrepQuery R () RowSparScimUserTimes
selectSparScimUserTimesAll = "SELECT uid, created_at, last_updated_at FROM scim_user_times"

readSparScimUserTimesAll :: Env -> ConduitM () [RowSparScimUserTimes] IO ()
readSparScimUserTimesAll Env {..} =
  transPipe (runClient envSpar) $
    paginateC selectSparScimUserTimesAll (paramsP LocalQuorum () envPageSize) x5

exportSparScimUserTimesFull :: Env -> FilePath -> IO ()
exportSparScimUserTimesFull env path = do
  putStrLn $ "Exporting " <> "spar.scim_user_times" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readSparScimUserTimesAll env
        .| sinkJsonLines handle

insertSparScimUserTimes :: PrepQuery W RowSparScimUserTimes ()
insertSparScimUserTimes =
  "INSERT INTO scim_user_times (uid, created_at, last_updated_at) VALUES (?, ?, ?)"

importSparScimUserTimes :: Env -> FilePath -> IO ()
importSparScimUserTimes Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "spar.scim_user_times"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envSpar) (sinkTableRows insertSparScimUserTimes)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

-- spar.user

type RowSparUser = (Maybe Text, Maybe Text, Maybe UUID)

selectSparUserAll :: PrepQuery R () RowSparUser
selectSparUserAll = "SELECT issuer, sso_id, uid FROM user"

readSparUserAll :: Env -> ConduitM () [RowSparUser] IO ()
readSparUserAll Env {..} =
  transPipe (runClient envSpar) $
    paginateC selectSparUserAll (paramsP LocalQuorum () envPageSize) x5

exportSparUserFull :: Env -> FilePath -> IO ()
exportSparUserFull env path = do
  putStrLn $ "Exporting " <> "spar.user" <> " to " <> path
  withBinaryFile path WriteMode $ \handle ->
    runConduit $
      readSparUserAll env
        .| sinkJsonLines handle

insertSparUser :: PrepQuery W RowSparUser ()
insertSparUser =
  "INSERT INTO user (issuer, sso_id, uid) VALUES (?, ?, ?)"

importSparUser :: Env -> FilePath -> IO ()
importSparUser Env {..} path = do
  exists <- doesFileExist path
  if exists
    then do
      putStrLn $ "Importing " <> path <> " to " <> "spar.user"
      withBinaryFile path ReadMode $ \handle ->
        runConduit $
          sourceJsonLines handle
            .| transPipe (runClient envSpar) (sinkTableRows insertSparUser)
    else do
      putStrLn $ "Skipping because not found: " <> path
      pure ()

importAllTables :: Env -> IO ()
importAllTables env@Env {..} = do
  importBrigClients env (envTargetPath </> "brig.clients")
  importBrigConnection env (envTargetPath </> "brig.connection")
  importBrigLoginCodes env (envTargetPath </> "brig.login_codes")
  importBrigPasswordReset env (envTargetPath </> "brig.password_reset")
  importBrigPrekeys env (envTargetPath </> "brig.prekeys")
  importBrigProperties env (envTargetPath </> "brig.properties")
  importBrigRichInfo env (envTargetPath </> "brig.rich_info")
  importBrigUser env (envTargetPath </> "brig.user")
  importBrigUserHandle env (envTargetPath </> "brig.user_handle")
  importBrigUserKeys env (envTargetPath </> "brig.user_keys")
  importGalleyBillingTeamMember env (envTargetPath </> "galley.billing_team_member")
  importGalleyClients env (envTargetPath </> "galley.clients")
  importGalleyConversation env (envTargetPath </> "galley.conversation")
  importGalleyMember env (envTargetPath </> "galley.member")
  importGalleyTeam env (envTargetPath </> "galley.team")
  importGalleyTeamConv env (envTargetPath </> "galley.team_conv")
  importGalleyTeamFeatures env (envTargetPath </> "galley.team_features")
  importGalleyTeamMember env (envTargetPath </> "galley.team_member")
  importGalleyTeamNotifications env (envTargetPath </> "galley.team_notifications")
  importGalleyUser env (envTargetPath </> "galley.user")
  importGalleyUserTeam env (envTargetPath </> "galley.user_team")
  importGundeckNotifications env (envTargetPath </> "gundeck.notifications")
  importSparScimExternal env (envTargetPath </> "spar.scim_external")
  importSparScimUserTimes env (envTargetPath </> "spar.scim_user_times")
  importSparUser env (envTargetPath </> "spar.user")

exportAllTablesFull :: Env -> IO ()
exportAllTablesFull env@Env {..} = do
  exportBrigClientsFull env (envTargetPath </> "brig.clients")
  exportBrigConnectionFull env (envTargetPath </> "brig.connection")
  exportBrigLoginCodesFull env (envTargetPath </> "brig.login_codes")
  exportBrigPasswordResetFull env (envTargetPath </> "brig.password_reset")
  exportBrigPrekeysFull env (envTargetPath </> "brig.prekeys")
  exportBrigPropertiesFull env (envTargetPath </> "brig.properties")
  exportBrigRichInfoFull env (envTargetPath </> "brig.rich_info")
  exportBrigUserFull env (envTargetPath </> "brig.user")
  exportBrigUserHandleFull env (envTargetPath </> "brig.user_handle")
  exportBrigUserKeysFull env (envTargetPath </> "brig.user_keys")
  exportGalleyBillingTeamMemberFull env (envTargetPath </> "galley.billing_team_member")
  exportGalleyClientsFull env (envTargetPath </> "galley.clients")
  exportGalleyConversationFull env (envTargetPath </> "galley.conversation")
  exportGalleyMemberFull env (envTargetPath </> "galley.member")
  exportGalleyTeamFull env (envTargetPath </> "galley.team")
  exportGalleyTeamConvFull env (envTargetPath </> "galley.team_conv")
  exportGalleyTeamFeaturesFull env (envTargetPath </> "galley.team_features")
  exportGalleyTeamMemberFull env (envTargetPath </> "galley.team_member")
  exportGalleyTeamNotificationsFull env (envTargetPath </> "galley.team_notifications")
  exportGalleyUserFull env (envTargetPath </> "galley.user")
  exportGalleyUserTeamFull env (envTargetPath </> "galley.user_team")
  exportGundeckNotificationsFull env (envTargetPath </> "gundeck.notifications")
  exportSparScimExternalFull env (envTargetPath </> "spar.scim_external")
  exportSparScimUserTimesFull env (envTargetPath </> "spar.scim_user_times")
  exportSparUserFull env (envTargetPath </> "spar.user")
