{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts   #-}
{-# LANGUAGE NoImplicitPrelude  #-}
{-# LANGUAGE OverloadedStrings  #-}
{-# LANGUAGE RecordWildCards    #-}
{-# LANGUAGE ViewPatterns       #-}
module Stackage.Curator.UploadIndex
    ( uploadIndex
    ) where

import System.Directory (getAppUserDataDirectory)
import Distribution.Package (Dependency)
import Filesystem (isDirectory, createTree, isFile, rename)
import Filesystem.Path (parent)
import Control.Concurrent        (threadDelay, getNumCapabilities)
import Control.Concurrent.Async  (withAsync)
import Data.Default.Class        (def)
import Data.Semigroup            (Max (..), Option (..))
import Data.Text.Read            (decimal)
import Data.Time
import Data.Yaml                 (decodeFileEither, encodeFile, decodeEither')
import Network.HTTP.Client
import Network.HTTP.Client.Conduit (bodyReaderSource)
import Network.HTTP.Client.TLS   (tlsManagerSettings)
import Stackage.BuildConstraints
import Stackage.BuildPlan
import Stackage.CheckBuildPlan
import Stackage.PerformBuild
import Stackage.Prelude
import Stackage.ServerBundle
import Stackage.UpdateBuildPlan
import Stackage.Upload
import System.Environment        (lookupEnv)
import System.IO                 (BufferMode (LineBuffering), hSetBuffering)
import Control.Monad.Trans.Unlift (askRunBase, MonadBaseUnlift)
import Data.Function (fix)
import Control.Concurrent.Async (Concurrently (..))
import Stackage.Curator.UploadDocs (uploadDocs)
import Stackage.Install (defaultIndexLocation)
import Stackage.PackageIndex.Conduit
import qualified Codec.Archive.Tar as Tar
import Data.Conduit.Lazy (lazyConsume)
import Codec.Compression.GZip (compress)
import           Network.AWS                   (Credentials (Discover), Env,
                                                Region (NorthVirginia), getEnv,
                                                send)
import           Network.AWS.Data              (toBody)
import           Network.AWS.S3                (ObjectCannedACL (PublicRead),
                                                poACL, poCacheControl,
                                                poContentEncoding,
                                                poContentType, putObject)
import Stackage.Curator.UploadDocs (upload)

uploadIndex
    :: FilePath -- ^ build plan
    -> Target
    -> Text -- ^ bucket
    -> Text -- ^ key prefix
    -> IO ()
uploadIndex bpFile target bucket prefix = do
    env <- getEnv NorthVirginia Discover
    bp <- decodeFileEither (fpToString bpFile) >>= either throwM return
    let toInclude = getToInclude bp
    runResourceT $ do
        entries <- lazyConsume
            $  sourceAllCabalFiles defaultIndexLocation
            $= filterC toInclude
            $= mapC cfeEntry
        let lbs = compress $ Tar.write entries
            key = concat
                [ prefix
                , targetSlug target
                , ".tar.gz"
                ]
        sourceLazy lbs $$ upload False env bucket key

getToInclude :: BuildPlan -> CabalFileEntry -> Bool
getToInclude bp =
    go
  where
    go cfe = lookup (cfeName cfe) packages == Just (cfeVersion cfe)

    packages = siCorePackages (bpSystemInfo bp) ++
               (ppVersion <$> bpPackages bp)