content: 
  
  module Test.Sandwich.Contexts.Kubernetes.MinioS3Server.Parsing (
    parseMinioUserAndPassword
    , transformKustomizeChunks
    ) where
  
  import Control.Lens
  import Data.Aeson (FromJSON)
  import qualified Data.Aeson as A
  import Data.Aeson.Lens
  import qualified Data.Map as M
  import Data.String.Interpolate
  import Data.Text as T
  import qualified Data.Yaml as Yaml
  import Kubernetes.OpenAPI.Model as Kubernetes
  import Relude
  import Safe (headMay)
  import Test.Sandwich.Contexts.Kubernetes.Util.Aeson
  import Text.Regex.TDFA
  
  
  parseMinioUserAndPassword :: Text -> Maybe (Text, Text)
  parseMinioUserAndPassword txt = case (userValues, passwordValues) of
    (Just (_before, _fullMatch, _after, [user]), Just (_, _, _, [password])) -> Just (user, toText password)
    _ -> Nothing
    where
      userValues :: Maybe (Text, Text, Text, [Text]) = txt =~~ ([i|MINIO_ROOT_USER="([^"]*)"|] :: Text)
      passwordValues :: Maybe (Text, Text, Text, [Text]) = txt =~~ ([i|MINIO_ROOT_PASSWORD="([^"]*)"|] :: Text)
  
  -- testInput :: Text
  -- testInput = [__i|export MINIO_ROOT_USER="WXSTFUWIRS04LMGIMJGV"
  --                  export MINIO_ROOT_PASSWORD="NCDCfTaiXcGHq8QRfSaXMAWOXgdrhpGwPSkoYMWf"|]
  
  transformKustomizeChunks :: String -> String -> [Text] -> Either String ((Text, Text), Text)
  transformKustomizeChunks namespace deploymentName initialChunks = do
    userAndPassword <- getUserAndPassword initialChunks
  
    return (userAndPassword, finalYaml)
  
    where
      finalYaml = initialChunks
                -- Don't include a kind: Namespace
                & Relude.filter (not . isNamespace)
  
                -- Set metadata.namespace on all values
                & fmap (setMetaNamespace namespace)
  
                -- Disable TLS
                & fmap disableTLS
  
                -- Set deployment name
                & fmap (setDeploymentNameAndPoolSize deploymentName)
  
                -- Combine everything into multi-document Yaml
                & T.intercalate "---\n"
  
  getUserAndPassword :: [Text] -> Either String (Text, Text)
  getUserAndPassword chunks = case headMay (mapMaybe getUserAndPassword' chunks) of
    Nothing -> Left "Couldn't find user/password YAML."
    Just x -> Right x
    where
      getUserAndPassword' :: Text -> Maybe (Text, Text)
      getUserAndPassword' (decode -> Right (V1Secret {v1SecretMetadata=(Just (V1ObjectMeta {v1ObjectMetaName=(Just "storage-configuration")}))
                                                     , v1SecretStringData=(Just (M.lookup "config.env" -> Just t))
                                                     }))
        = parseMinioUserAndPassword t
      getUserAndPassword' _ = Nothing
  
  isNamespace :: Text -> Bool
  isNamespace (decode -> Right (A.Object (aesonLookup "kind" -> Just (A.String "Namespace")))) = True
  isNamespace _ = False
  
  setMetaNamespace :: String -> Text -> Text
  setMetaNamespace namespace (decode -> Right (A.Object obj1@(aesonLookup "metadata" -> Just (A.Object obj2@(aesonLookup "namespace" -> Just (A.String _)))))) =
    decodeUtf8 (Yaml.encode obj1')
    where
      obj1' :: A.Value
      obj1' = A.Object (aesonInsert "metadata" obj2' obj1)
  
      obj2' :: A.Value
      obj2' = A.Object (aesonInsert "namespace" (A.String (toText namespace)) obj2)
  setMetaNamespace _ t = t
  
  -- Do the steps to disable TLS in the tenant CRD.
  -- See https://min.io/docs/minio/kubernetes/upstream/reference/operator-crd.html#tenantspec
  disableTLS :: Text -> Text
  disableTLS (decode -> Right x@(A.Object (aesonLookup "kind" -> Just (A.String "Tenant")))) = decodeUtf8 (Yaml.encode x')
    where
      x' = x
         & set (_Object . ix "spec" . _Object . ix "requestAutoCert") (A.Bool False)
         & set (_Object . ix "spec" . _Object . at "externalCertSecret") Nothing
  disableTLS t = t
  
  setDeploymentNameAndPoolSize :: String -> Text -> Text
  setDeploymentNameAndPoolSize deploymentName (decode -> Right x@(A.Object (aesonLookup "kind" -> Just (A.String "Tenant")))) = decodeUtf8 (Yaml.encode x')
    where
      x' = x
         & set (_Object . ix "metadata" . _Object . ix "name") (A.String (toText deploymentName))
         & set (_Object . ix "spec" . _Object . ix "pools" . _Array . ix 0 . _Object . ix "servers") (A.Number 1)
  setDeploymentNameAndPoolSize _ t = t
  
  decode :: FromJSON a => Text -> Either Yaml.ParseException a
  decode = Yaml.decodeEither' . encodeUtf8
  