{-# LANGUAGE MultiWayIf #-}

module Simplex.Messaging.Transport.HTTP2.File
  ( fileBlockSize,
    hReceiveFile,
    hSendFile,
    getFileChunk,
  ) where

import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.ByteString.Builder (Builder, byteString)
import Data.Int (Int64)
import Data.Word (Word32)
import GHC.IO.Handle.Internals (ioe_EOF)
import System.IO (Handle)

fileBlockSize :: Int
fileBlockSize = 16384

hReceiveFile :: (Int -> IO ByteString) -> Handle -> Word32 -> IO Int64
hReceiveFile _ _ 0 = pure 0
hReceiveFile getBody h size = get $ fromIntegral size
  where
    get sz = do
      ch <- getBody fileBlockSize
      let chSize = fromIntegral $ B.length ch
      if
        | chSize > sz -> pure (chSize - sz)
        | chSize > 0 -> B.hPut h ch >> get (sz - chSize)
        | otherwise -> pure (-sz)

hSendFile :: Handle -> (Builder -> IO ()) -> Word32 -> IO ()
hSendFile h send = go
  where
    go 0 = pure ()
    go sz =
      getFileChunk h sz >>= \ch -> do
        send $ byteString ch
        go $ sz - fromIntegral (B.length ch)

getFileChunk :: Handle -> Word32 -> IO ByteString
getFileChunk h sz = do
  ch <- B.hGet h fileBlockSize
  if B.null ch
    then ioe_EOF
    else pure $ B.take (fromIntegral sz) ch -- sz >= xftpBlockSize
