{-# LANGUAGE DataKinds     #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -w #-}

module Cut.Lib
  ( entryPoint
  , combineDir
  )
where

import           Control.Lens
import           Control.Monad
import           Control.Monad.Catch
import           Control.Monad.IO.Class
import           Control.Monad.IO.Unlift
import           Cut.Analyze
import           Cut.CutVideo
import           Cut.Ffmpeg
import           Cut.Options
import           Cut.SplitVideo
import           Data.Bifunctor
import           Data.Either
import qualified Data.Text                     as Text
import qualified Data.Text.IO                  as Text
import           Data.Text.Lens
import           Options.Applicative
import           Options.Generic
import           Shelly                  hiding ( FilePath )
import           System.IO.Temp
import           Text.Regex.TDFA         hiding ( empty
                                                , extract
                                                )

entryPoint :: (MonadMask m, MonadUnliftIO m) => m ()
entryPoint = catch main
  $ \exec -> liftIO (print ("Uncaught exception: ", exec :: SomeException))

main :: (MonadMask m, MonadUnliftIO m) => m ()
main = do
  options <- liftIO readSettings
  liftIO $ putStr "started with options: "
  liftIO $ print options

  parsed <- detect options
  case options ^. work_dir of
    Nothing ->
      withTempDirectory "/tmp" "streamedit" $ liftIO . runEdit options parsed
    Just x -> liftIO $ runEdit options parsed x

runEdit :: Options -> [Interval Sound] -> FilePath -> IO ()
runEdit options parsed temp = do
  extract options temp parsed
  shelly $ combineDir options temp
  getMusic options temp

combineDir :: Options -> FilePath -> Sh ()
combineDir options temp = do
  res <- lsT $ fromText $ Text.pack temp
  let paths :: Text
      paths = Text.unlines $ flip (<>) "'" . ("file '" <>) <$> res
  writefile (fromText $ Text.pack $ temp <> "/input.txt") paths
  combine temp

readSettings :: IO Options
readSettings = customExecParser (prefs showHelpOnError) $ info
  parseRecord
  (fullDesc <> Options.Applicative.header "Cut the crap" <> progDesc
    "Automated video extracting, can cut out silences"
  )

musicFile :: FilePath
musicFile = "music.mp3"

withMusicFile :: FilePath
withMusicFile = "combined.mkv"

getMusic :: Options -> FilePath -> IO ()
getMusic opt' tempfiles = do
  res <- case opt' ^. music_track of
    Nothing -> pure $ Text.pack combinedFile
    Just x  -> do
      shelly $ ffmpeg $ args x
      shelly $ combineMusic tempfiles
      pure $ Text.pack (tempfiles <> "/" <> withMusicFile)
  putStrLn "done get music"
  shelly $ cp (fromText res) (opt' ^. out_file . packed . to fromText)
  pure ()
 where -- https://stackoverflow.com/questions/7333232/how-to-concatenate-two-mp4-files-using-ffmpeg
  combinedFile = tempfiles <> "/" <> combineOutput
  args x' =
    [ "-i"
    , opt' ^. in_file . packed
    , "-map"
    , "0:" <> Text.pack (show x')
    , Text.pack (tempfiles <> "/" <> musicFile)
    ]

combineMusic :: FilePath -> Sh ()
combineMusic tempfiles = void $ ffmpeg args
 where -- https://stackoverflow.com/questions/7333232/how-to-concatenate-two-mp4-files-using-ffmpeg
  args =
    [ "-i"
    , Text.pack $ tempfiles <> "/" <> combineOutput
    , "-i"
    , Text.pack $ tempfiles <> "/" <> musicFile
    , "-filter_complex"
    , "[0:a][1:a]amerge=inputs=2[a]"
    , "-map"
    , "0:v"
    , "-map"
    , "[a]"
    , "-c:v"
    , "copy"
    , "-c:a"
    , "mp3"
    , "-ac"
    , "2"
    , "-shortest"
    , Text.pack (tempfiles <> "/" <> withMusicFile)
    ]