module Language.Haskell.Format.HIndent
  ( autoSettings
  , formatter
  , defaultFormatter
  ) where

import           Data.ByteString.Builder
import           Data.ByteString.Lazy             as L
import qualified Data.Text                        as Text
import           Data.Text.Encoding               as Encoding
import qualified Data.Yaml                        as Y
import           HIndent
import           HIndent.Types
import           Language.Haskell.Exts.Extension  (Extension)
import           Path
import qualified Path.Find                        as Path
import qualified Path.IO                          as Path

import           Language.Haskell.Format.Internal
import           Language.Haskell.Format.Types

data Settings =
  Settings Config
           (Maybe [Extension])

defaultFormatter :: IO Formatter
defaultFormatter = formatter <$> autoSettings

autoSettings :: IO Settings
autoSettings = do
  config <- getConfig
  return $ Settings config $ Just defaultExtensions

-- | Read config from a config file, or return 'defaultConfig'.
getConfig :: IO Config
getConfig = do
  cur <- Path.getCurrentDir
  homeDir <- Path.getHomeDir
  mfile <-
    Path.findFileUp
      cur
      ((== ".hindent.yaml") . toFilePath . filename)
      (Just homeDir)
  case mfile of
    Nothing -> return defaultConfig
    Just file -> do
      result <- Y.decodeFileEither (toFilePath file)
      case result of
        Left e       -> error (show e)
        Right config -> return config

formatter :: Settings -> Formatter
formatter = mkFormatter . hindent

hindent :: Settings -> HaskellSource -> Either String HaskellSource
hindent (Settings config extensions) (HaskellSource filepath source) =
  HaskellSource filepath . unpackBuilder <$>
  reformat config extensions Nothing sourceText
  where
    sourceText = Encoding.encodeUtf8 . Text.pack $ source
    unpackBuilder =
      Text.unpack . Encoding.decodeUtf8 . L.toStrict . toLazyByteString