module ElmFormat.Messages (PromptMessage(..), InfoMessage(..), ErrorMessage(..)) where

-- inspired by:
-- https://wiki.haskell.org/Internationalization_of_Haskell_programs_using_Haskell_data_types

import Prelude ()
import Relude

import CommandLine.InfoFormatter (ToConsole(..), Loggable(..))
import CommandLine.ResolveFiles as ResolveFiles
import qualified Data.Text as Text
import qualified ElmFormat.Version
import ElmVersion
import qualified Reporting.Annotation as A
import qualified Reporting.Error.Syntax as Syntax
import qualified Data.Aeson as Aeson
import Data.Aeson ((.=))


data InfoMessage
  = ProcessingFile FilePath
  | FileWouldChange ElmVersion FilePath
  | ParseError FilePath [A.Located Syntax.Error]
  | JsonParseError FilePath Text


data PromptMessage
    = FilesWillBeOverwritten [FilePath]


data ErrorMessage
  = BadInputFiles [ResolveFiles.Error]
  | NoInputs
  | SingleOutputWithMultipleInputs
  | TooManyInputs
  | OutputAndValidate
  | MustSpecifyVersionWithUpgrade ElmVersion


showFiles :: [FilePath] -> Text
showFiles = unlines . fmap (\filename -> "    " <> Text.pack filename)


instance ToConsole PromptMessage where
    toConsole = \case
        FilesWillBeOverwritten filePaths ->
            unlines
                [ "This will overwrite the following files to use Elm's preferred style:"
                , ""
                , showFiles filePaths
                , "This cannot be undone! Make sure to back up these files before proceeding."
                , ""
                , "Are you sure you want to overwrite these files with formatted versions? (y/n)"
                ]


instance ToConsole InfoMessage where
    toConsole = \case
        ProcessingFile file ->
            "Processing file " <> Text.pack file

        FileWouldChange _ file ->
            "File would be changed " <> Text.pack file

        ParseError inputFile errs ->
            let
                location =
                    Text.pack $
                    case errs of
                        [] -> inputFile
                        (A.At (A.Region (A.Position line col) _) _) : _ -> inputFile ++ ":" ++ show line ++ ":" ++ show col
            in
            "Unable to parse file " <> location <> " To see a detailed explanation, run elm make on the file."

        JsonParseError inputFile err ->
            "Unable to parse JSON file " <> Text.pack inputFile <> "\n\n" <> err


instance Loggable InfoMessage where
    jsonInfoMessage =
        let
            fileMessage filename message =
                Aeson.pairs $ mconcat
                    [ "path" .= (filename :: FilePath)
                    , "message" .= (message :: String)
                    ]
        in
        \case
        ProcessingFile _ -> Nothing
        FileWouldChange elmVersion file ->
            Just $ fileMessage file $
                "File is not formatted with elm-format-" <> ElmFormat.Version.asString
                <> " --elm-version=" <> show elmVersion
        ParseError inputFile _ ->
            Just $ fileMessage inputFile "Error parsing the file"
        JsonParseError inputFile _ ->
            Just $ fileMessage inputFile "Error parsing the JSON file"


instance ToConsole ErrorMessage where
    toConsole = \case
        BadInputFiles filePaths ->
            unlines
                [ "There was a problem reading one or more of the specified INPUT paths:"
                , ""
                , unlines $ map ((<>) "    " . toConsole) filePaths
                , "Please check the given paths."
                ]

        SingleOutputWithMultipleInputs ->
            unlines
                [ "Can't write to the OUTPUT path, because multiple .elm files have been specified."
                , ""
                , "Please remove the --output argument. The .elm files in INPUT will be formatted in place."
                ]

        TooManyInputs ->
            "Too many input sources! Please only provide one of either INPUT or --stdin"

        OutputAndValidate ->
            "Cannot use --output and --validate together"

        MustSpecifyVersionWithUpgrade elmVersion ->
            "I can only upgrade code to specific Elm versions.  To make sure I'm doing what you expect, you must also specify --elm-version=" <> Text.pack (show elmVersion) <> " when you use --upgrade."

        NoInputs ->
            error "Error case NoInputs should be handled elsewhere.  Please report this issue at https://github.com/avh4/elm-format/issues"
