module System.FilePath.TH where

import Prelude

import Control.Monad ((<=<))
import Data.FileEmbed (makeRelativeToProject)
import Language.Haskell.TH (Loc(Loc), Exp, Q, loc_filename, location, runIO, stringE)
import System.Directory (canonicalizePath, getCurrentDirectory)
import System.FilePath ((</>), takeDirectory)

fileRelativeToAbsolute :: String -> Q Exp
fileRelativeToAbsolute = stringE <=< fileRelativeToAbsoluteStr

-- | Use a path relative to the source file in which you're writing the path instead of relative to the working
-- directory in which that source file will be compiled.
--
-- e.g. if this source file is in `my-project/src/Foo/Bar.hs`, `fileRelativeToAbsoluteStr
-- "../../../config/settings.yml"` will load the path at `my-project/config/settings.yml`.
--
-- If this function is provided an absolute path, it will simply canonicalize that path
-- by calling 'System.Directory.canonicalizePath' rather than compute an absolute path from
-- a relative path.
fileRelativeToAbsoluteStr :: String -> Q String
fileRelativeToAbsoluteStr absoluteFilePath@('/':_) =
  runIO . canonicalizePath $ absoluteFilePath
fileRelativeToAbsoluteStr relativeFilePath = do
  Loc {..} <- location
  currentDir <- runIO getCurrentDirectory
  let baseDir = takeDirectory loc_filename
  runIO $ canonicalizePath $ currentDir </> baseDir </> relativeFilePath

fileRelativeToProject :: FilePath -> Q Exp
fileRelativeToProject = stringE <=< makeRelativeToProject