module Ormolu.Integration.CLISpec (spec) where

import Control.Monad (forM_)
import Ormolu.Integration.Utils (ProcessSpec (..), getFourmoluExe, proc, readFrom, readProcess)
import System.Directory (createDirectoryIfMissing)
import System.FilePath (takeDirectory, (</>))
import System.IO.Temp (withSystemTempDirectory)
import Test.Hspec

spec :: Spec
spec =
  describe "Fourmolu CLI functionality" . beforeAll getFourmoluExe $ do
    it "formats stdin when no files specified" $ \fourmoluExe -> do
      stdout <- readFrom $ (proc fourmoluExe ["--no-cabal"]) {procStdin = unformattedCode}
      stdout `shouldBe` formattedCode

    it "formats stdin when stdin specified" $ \fourmoluExe -> do
      stdout <- readFrom $ (proc fourmoluExe ["--no-cabal", "-"]) {procStdin = unformattedCode}
      stdout `shouldBe` formattedCode

    it "finds config file in current directory when formatting stdin" $ \fourmoluExe ->
      withTempDir $ \tmpdir -> do
        writeFile' (tmpdir </> "fourmolu.yaml") "single-constraint-parens: never"
        stdout <-
          readFrom $
            (proc fourmoluExe ["--no-cabal", "-"])
              { procStdin = "f :: (Show a) => a -> String",
                procCwd = Just tmpdir
              }
        stdout `shouldBe` "f :: Show a => a -> String\n"

    it "finds config file in ancestor directory when formatting stdin" $ \fourmoluExe ->
      withTempDir $ \tmpdir -> do
        writeFile' (tmpdir </> "fourmolu.yaml") "single-constraint-parens: never"
        let cwd = tmpdir </> "a" </> "b" </> "c"
        createDirectoryIfMissing True cwd
        stdout <-
          readFrom $
            (proc fourmoluExe ["--no-cabal", "-"])
              { procStdin = "f :: (Show a) => a -> String",
                procCwd = Just cwd
              }
        stdout `shouldBe` "f :: Show a => a -> String\n"

    it "finds config file in directory of input file" $ \fourmoluExe ->
      withTempDir $ \tmpdir -> do
        writeFile' (tmpdir </> "fourmolu.yaml") "single-constraint-parens: never"
        writeFile' (tmpdir </> "input.hs") "f :: (Show a) => a -> String"
        stdout <-
          readFrom $
            (proc fourmoluExe ["--no-cabal", "input.hs"])
              { procCwd = Just tmpdir
              }
        stdout `shouldBe` "f :: Show a => a -> String\n"

    it "finds config file in XDG directory" $ \fourmoluExe ->
      withTempDir $ \tmpdir -> do
        let configDir = tmpdir </> "config"
        writeFile' (configDir </> "fourmolu.yaml") "single-constraint-parens: never"
        stdout <-
          readFrom $
            (proc fourmoluExe ["--no-cabal", "-"])
              { procStdin = "f :: (Show a) => a -> String",
                procCwd = Just tmpdir,
                procExtraEnv = [("XDG_CONFIG_HOME", configDir)]
              }
        stdout `shouldBe` "f :: Show a => a -> String\n"

    it "uses specified config file" $ \fourmoluExe ->
      withTempDir $ \tmpdir -> do
        let configFile = tmpdir </> "foo" </> "my-config.yaml"
        let inputFile = tmpdir </> "bar" </> "input.hs"
        writeFile' configFile "single-constraint-parens: never"
        writeFile' inputFile "f :: (Show a) => a -> String"
        stdout <-
          readFrom $
            (proc fourmoluExe ["--no-cabal", "--config", configFile, inputFile])
              { procCwd = Just tmpdir
              }
        stdout `shouldBe` "f :: Show a => a -> String\n"

    it "recursively finds files in directories" $ \fourmoluExe -> do
      withTempDir $ \tmpdir -> do
        let hsFile = tmpdir </> "test.hs"
        writeFile' hsFile unformattedCode

        output <- readProcess fourmoluExe [tmpdir]
        output `shouldBe` formattedCode

    it "ignores files in specific directories" $ \fourmoluExe -> do
      withTempDir $ \tmpdir -> do
        let testFiles =
              [ tmpdir </> "test1.hs",
                tmpdir </> "foo/test2.hs"
              ]
        let ignoredFiles =
              [ tmpdir </> ".stack-work/test.hs",
                tmpdir </> "dist-newstyle/test.hs"
              ]
        forM_ (testFiles ++ ignoredFiles) $ \fp -> do
          writeFile' fp unformattedCode

        _ <- readProcess fourmoluExe ["-i", tmpdir]
        forM_ testFiles $ \fp -> do
          output <- readFile fp
          output `shouldBe` formattedCode
        forM_ ignoredFiles $ \fp -> do
          output <- readFile fp
          output `shouldBe` unformattedCode
  where
    withTempDir = withSystemTempDirectory "fourmolu-cli-test"
    writeFile' fp s = do
      createDirectoryIfMissing True (takeDirectory fp)
      writeFile fp s
    unformattedCode = "main=print(1+1)\n"
    formattedCode = "main = print (1 + 1)\n"
