{-# LANGUAGE TemplateHaskell #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2025 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 Wire.AppStore where

import Data.Aeson
import Data.Default
import Data.Id
import Data.Range
import Data.UUID
import Imports
import Polysemy
import Wire.API.PostgresMarshall
import Wire.API.User
import Wire.Arbitrary

data StoredApp = StoredApp
  { id :: UserId,
    teamId :: TeamId,
    meta :: Object,
    category :: Category,
    description :: Range 0 300 Text,
    creator :: UserId
  }
  deriving (Eq, Ord, Show)

data StoredAppUpdate = MkStoredAppUpdate
  { category :: Maybe Category,
    description :: Maybe (Range 0 300 Text)
  }
  deriving stock (Eq, Ord, Show, Generic)
  deriving (Arbitrary) via GenericUniform StoredAppUpdate

instance Default StoredAppUpdate where
  def = MkStoredAppUpdate Nothing Nothing

-- The `PostgresMarshall` instances are here in this module -- as
-- having them elsewhere would make them orphan instances of
-- `StoredApp`.
instance PostgresMarshall (UUID, UUID, Value, Text, Text, UUID) StoredApp where
  postgresMarshall app =
    ( postgresMarshall app.id,
      postgresMarshall app.teamId,
      postgresMarshall app.meta,
      postgresMarshall (fromCategory app.category),
      postgresMarshall (fromRange app.description),
      postgresMarshall app.creator
    )

instance PostgresUnmarshall (UUID, UUID, Value, Text, Text, UUID) StoredApp where
  postgresUnmarshall (uid, teamId, meta, category, description, creator) =
    StoredApp
      <$> postgresUnmarshall uid
      <*> postgresUnmarshall teamId
      <*> postgresUnmarshall meta
      <*> postgresUnmarshall (Category category)
      <*> (maybe (Left "description out of bounds") Right . checked @0 @300 =<< postgresUnmarshall description)
      <*> postgresUnmarshall creator

data AppStoreError = NotFound
  deriving (Eq, Show)

data AppStore m a where
  CreateApp :: StoredApp -> AppStore m ()
  GetApp :: UserId -> TeamId -> AppStore m (Maybe StoredApp)
  GetApps :: TeamId -> AppStore m [StoredApp]
  UpdateApp :: TeamId -> UserId -> StoredAppUpdate -> AppStore m (Either AppStoreError ())
  DeleteApp :: UserId -> TeamId -> AppStore m ()

makeSem ''AppStore
