content: {-# LANGUAGE OverloadedStrings #-}
  module Reporting.Exit
    ( Init(..), initToReport
    , Diff(..), diffToReport
    , Make(..), makeToReport
    , Bump(..), bumpToReport
    , Repl(..), replToReport
    , Publish(..), publishToReport
    , Install(..), installToReport
    , Reactor(..), reactorToReport
    , newPackageOverview
    --
    , Solver(..)
    , Outline(..)
    , OutlineProblem(..)
    , Details(..)
    , DetailsBadDep(..)
    , PackageProblem(..)
    , RegistryProblem(..)
    , BuildProblem(..)
    , BuildProjectProblem(..)
    , DocsProblem(..)
    , Generate(..)
    --
    , toString
    , toStderr
    , toJson
    -- @LAMDERA exposed
    , toDetailsReport
    , toHttpErrorReport
    )
    where
  
  
  import qualified Data.ByteString as BS
  import qualified Data.ByteString.UTF8 as BS_UTF8
  import qualified Data.List as List
  import qualified Data.Map as Map
  import qualified Data.Name as N
  import qualified Data.NonEmptyList as NE
  import qualified Network.HTTP.Client as HTTP
  import qualified Network.HTTP.Types.Header as HTTP
  import qualified Network.HTTP.Types.Status as HTTP
  import qualified System.FilePath as FP
  import System.FilePath ((</>), (<.>))
  
  import qualified Elm.Constraint as C
  import qualified Elm.Magnitude as M
  import qualified Elm.ModuleName as ModuleName
  import qualified Elm.Package as Pkg
  import qualified Elm.Version as V
  import qualified File
  import qualified Http
  import qualified Json.Decode as Decode
  import qualified Json.Encode as Encode
  import qualified Json.String as Json
  import Parse.Primitives (Row, Col)
  import qualified Reporting.Annotation as A
  import Reporting.Doc ((<>))
  import qualified Reporting.Doc as D
  import qualified Reporting.Error.Import as Import
  import qualified Reporting.Error.Json as Json
  import qualified Reporting.Exit.Help as Help
  import qualified Reporting.Error as Error
  import qualified Reporting.Render.Code as Code
  
  
  import Lamdera
  import qualified Lamdera.Error
  import qualified Elm.Constraint as Con
  
  -- RENDERERS
  
  
  toString :: Help.Report -> String
  toString report =
    Help.toString (Help.reportToDoc report)
  
  
  toStderr :: Help.Report -> IO ()
  toStderr report =
    Help.toStderr (Help.reportToDoc report)
  
  
  toJson :: Help.Report -> Encode.Value
  toJson report =
    Help.reportToJson report
  
  
  
  -- INIT
  
  
  data Init
    = InitNoSolution [Pkg.Name]
    | InitNoOfflineSolution [Pkg.Name]
    | InitSolverProblem Solver
    | InitAlreadyExists
    | InitRegistryProblem RegistryProblem
  
  
  initToReport :: Init -> Help.Report
  initToReport exit =
    case exit of
      InitNoSolution pkgs ->
        Help.report "NO SOLUTION" Nothing
          "I tried to create an elm.json with the following direct dependencies:"
          [ D.indent 4 $ D.vcat $
              map (D.dullyellow . D.fromChars . Pkg.toChars) pkgs
          , D.reflow $
              "I could not find compatible versions though! This should not happen, so please\
              \ ask around one of the community forums at https://elm-lang.org/community to learn\
              \ what is going on!"
          ]
  
      InitNoOfflineSolution pkgs ->
        Help.report "NO OFFLINE SOLUTION" Nothing
          "I tried to create an elm.json with the following direct dependencies:"
          [ D.indent 4 $ D.vcat $
              map (D.dullyellow . D.fromChars . Pkg.toChars) pkgs
          , D.reflow $
              "I could not find compatible versions though, but that may be because I could not\
              \ connect to https://package.elm-lang.org to get the latest list of packages. Are\
              \ you able to connect to the internet? Please ask around one of the community\
              \ forums at https://elm-lang.org/community for help!"
          ]
  
      InitSolverProblem solver ->
        toSolverReport solver
  
      InitAlreadyExists ->
        Help.report "EXISTING PROJECT" Nothing
          "You already have an elm.json file, so there is nothing for me to initialize!"
          [ D.fillSep
              ["Maybe",D.green (D.fromChars (D.makeLink "init")),"can","help"
              ,"you","figure","out","what","to","do","next?"
              ]
          ]
  
      InitRegistryProblem problem ->
        toRegistryProblemReport "PROBLEM LOADING PACKAGE LIST" problem $
          "I need the list of published packages before I can start initializing projects"
  
  
  
  -- DIFF
  
  
  data Diff
    = DiffNoOutline
    | DiffBadOutline Outline
    | DiffApplication
    | DiffNoExposed
    | DiffUnpublished
    | DiffUnknownPackage Pkg.Name [Pkg.Name]
    | DiffUnknownVersion Pkg.Name V.Version [V.Version]
    | DiffDocsProblem V.Version DocsProblem
    | DiffMustHaveLatestRegistry RegistryProblem
    | DiffBadDetails Details
    | DiffBadBuild BuildProblem
  
  
  diffToReport :: Diff -> Help.Report
  diffToReport diff =
    case diff of
      DiffNoOutline ->
        Help.report "DIFF WHAT?" Nothing
          "I cannot find an elm.json so I am not sure what you want me to diff.\
          \ Normally you run `elm diff` from within a project!"
          [ D.reflow $ "If you are just curious to see a diff, try running this command:"
          , D.indent 4 $ D.green $ "elm diff elm/http 1.0.0 2.0.0"
          ]
  
      DiffBadOutline outline ->
        toOutlineReport outline
  
      DiffApplication ->
        Help.report "CANNOT DIFF APPLICATIONS" (Just "elm.json")
          "Your elm.json says this project is an application, but `elm diff` only works\
          \ with packages. That way there are previously published versions of the API to\
          \ diff against!"
          [ D.reflow $ "If you are just curious to see a diff, try running this command:"
          , D.indent 4 $ D.dullyellow $ "elm diff elm/json 1.0.0 1.1.2"
          ]
  
      DiffNoExposed ->
        Help.report "NO EXPOSED MODULES" (Just "elm.json")
          "Your elm.json has no \"exposed-modules\" which means there is no public API at\
          \ all right now! What am I supposed to diff?"
          [ D.reflow $
              "Try adding some modules back to the \"exposed-modules\" field."
          ]
  
      DiffUnpublished ->
        Help.report "UNPUBLISHED" Nothing
          "This package is not published yet. There is nothing to diff against!"
          []
  
      DiffUnknownPackage pkg suggestions ->
        Help.report "UNKNOWN PACKAGE" Nothing
          ( "I cannot find a package called:"
          )
          [ D.indent 4 $ D.red $ D.fromChars $ Pkg.toChars pkg
          , "Maybe you want one of these instead?"
          , D.indent 4 $ D.dullyellow $ D.vcat $ map (D.fromChars . Pkg.toChars) suggestions
          , "But check <https://package.elm-lang.org> to see all possibilities!"
          ]
  
      DiffUnknownVersion _pkg vsn realVersions ->
        Help.docReport "UNKNOWN VERSION" Nothing
          ( D.fillSep $
              [ "Version", D.red (D.fromVersion vsn)
              , "has", "never", "been", "published,", "so", "I"
              , "cannot", "diff", "against", "it."
              ]
          )
          [ "Here are all the versions that HAVE been published:"
          , D.indent 4 $ D.dullyellow $ D.vcat $
              let
                sameMajor v1 v2 = V._major v1 == V._major v2
                mkRow vsns = D.hsep $ map D.fromVersion vsns
              in
                map mkRow $ List.groupBy sameMajor (List.sort realVersions)
          , "Want one of those instead?"
          ]
  
      DiffDocsProblem version problem ->
        toDocsProblemReport problem $
          "I need the docs for " ++ V.toChars version ++ " to compute this diff"
  
      DiffMustHaveLatestRegistry problem ->
        toRegistryProblemReport "PROBLEM UPDATING PACKAGE LIST" problem $
          "I need the latest list of published packages before I do this diff"
  
      DiffBadDetails details ->
        toDetailsReport details
  
      DiffBadBuild buildProblem ->
        toBuildProblemReport buildProblem
  
  
  
  -- BUMP
  
  
  data Bump
    = BumpNoOutline
    | BumpBadOutline Outline
    | BumpApplication
    | BumpUnexpectedVersion V.Version [V.Version]
    | BumpMustHaveLatestRegistry RegistryProblem
    | BumpCannotFindDocs Pkg.Name V.Version DocsProblem
    | BumpBadDetails Details
    | BumpNoExposed
    | BumpBadBuild BuildProblem
  
  
  bumpToReport :: Bump -> Help.Report
  bumpToReport bump =
    case bump of
      BumpNoOutline ->
        Help.report "BUMP WHAT?" Nothing
          "I cannot find an elm.json so I am not sure what you want me to bump."
          [ D.reflow $
              "Elm packages always have an elm.json that says current the version number. If\
              \ you run this command from a directory with an elm.json file, I will try to bump\
              \ the version in there based on the API changes."
          ]
  
      BumpBadOutline outline ->
        toOutlineReport outline
  
      BumpApplication ->
        Help.report "CANNOT BUMP APPLICATIONS" (Just "elm.json")
          "Your elm.json says this is an application. That means it cannot be published\
          \ on <https://package.elm-lang.org> and therefore has no version to bump!"
          []
  
      BumpUnexpectedVersion vsn versions ->
        Help.docReport "CANNOT BUMP" (Just "elm.json")
          ( D.fillSep
              ["Your","elm.json","says","I","should","bump","relative","to","version"
              ,D.red (D.fromVersion vsn) <> ","
              ,"but","I","cannot","find","that","version","on","<https://package.elm-lang.org>."
              ,"That","means","there","is","no","API","for","me","to","diff","against","and"
              ,"figure","out","if","these","are","MAJOR,","MINOR,","or","PATCH","changes."
              ]
          )
          [ D.fillSep $
              ["Try","bumping","again","after","changing","the",D.dullyellow "\"version\"","in","elm.json"]
              ++ if length versions == 1 then ["to:"] else ["to","one","of","these:"]
          , D.vcat $ map (D.green . D.fromVersion) versions
          ]
  
      BumpMustHaveLatestRegistry problem ->
        toRegistryProblemReport "PROBLEM UPDATING PACKAGE LIST" problem $
          "I need the latest list of published packages before I can bump any versions"
  
      BumpCannotFindDocs _ version problem ->
        toDocsProblemReport problem $
          "I need the docs for " ++ V.toChars version ++ " to compute the next version number"
  
      BumpBadDetails details ->
        toDetailsReport details
  
      BumpNoExposed ->
        Help.docReport "NO EXPOSED MODULES" (Just "elm.json")
          ( D.fillSep $
              [ "To", "bump", "a", "package,", "the"
              , D.dullyellow "\"exposed-modules\"", "field", "of", "your"
              , "elm.json", "must", "list", "at", "least", "one", "module."
              ]
          )
          [ D.reflow $
              "Try adding some modules back to the \"exposed-modules\" field."
          ]
  
      BumpBadBuild problem ->
        toBuildProblemReport problem
  
  
  
  -- OVERVIEW OF VERSIONING
  
  
  newPackageOverview :: String
  newPackageOverview =
    unlines
      [ "This package has never been published before. Here's how things work:"
      , ""
      , "  - Versions all have exactly three parts: MAJOR.MINOR.PATCH"
      , ""
      , "  - All packages start with initial version " ++ V.toChars V.one
      , ""
      , "  - Versions are incremented based on how the API changes:"
      , ""
      , "        PATCH = the API is the same, no risk of breaking code"
      , "        MINOR = values have been added, existing values are unchanged"
      , "        MAJOR = existing values have been changed or removed"
      , ""
      , "  - I will bump versions for you, automatically enforcing these rules"
      , ""
      ]
  
  
  
  -- PUBLISH
  
  
  data Publish
    = PublishNoOutline
    | PublishBadOutline Outline
    | PublishBadDetails Details
    | PublishMustHaveLatestRegistry RegistryProblem
    | PublishApplication
    | PublishNotInitialVersion V.Version
    | PublishAlreadyPublished V.Version
    | PublishInvalidBump V.Version V.Version
    | PublishBadBump V.Version V.Version M.Magnitude V.Version M.Magnitude
    | PublishNoSummary
    | PublishNoExposed
    | PublishNoReadme
    | PublishShortReadme
    | PublishNoLicense
    | PublishBuildProblem BuildProblem
    | PublishMissingTag V.Version
    | PublishCannotGetTag V.Version Http.Error
    | PublishCannotGetTagData V.Version String BS.ByteString
    | PublishCannotGetZip Http.Error
    | PublishCannotDecodeZip String
    | PublishCannotGetDocs V.Version V.Version DocsProblem
    | PublishCannotRegister Http.Error
    | PublishNoGit
    | PublishLocalChanges V.Version
    --
    | PublishZipBadDetails Details
    | PublishZipApplication
    | PublishZipNoExposed
    | PublishZipBuildProblem BuildProblem
  
  
  publishToReport :: Publish -> Help.Report
  publishToReport publish =
    case publish of
      PublishNoOutline ->
        Help.report "PUBLISH WHAT?" Nothing
          "I cannot find an elm.json so I am not sure what you want me to publish."
          [ D.reflow $
              "Elm packages always have an elm.json that states the version number,\
              \ dependencies, exposed modules, etc."
          ]
  
      PublishBadOutline outline ->
        toOutlineReport outline
  
      PublishBadDetails problem ->
        toDetailsReport problem
  
      PublishMustHaveLatestRegistry problem ->
        toRegistryProblemReport "PROBLEM UPDATING PACKAGE LIST" problem $
          "I need the latest list of published packages to make sure this is safe to publish"
  
      PublishApplication ->
        Help.report "UNPUBLISHABLE" Nothing "I cannot publish applications, only packages!" []
  
      PublishNotInitialVersion vsn ->
        Help.docReport "INVALID VERSION" Nothing
          ( D.fillSep
              ["I","cannot","publish"
              ,D.red (D.fromVersion vsn)
              ,"as","the","initial","version."
              ]
          )
          [ D.fillSep
              ["Change","it","to",D.green "1.0.0","which","is"
              ,"the","initial","version","for","all","Elm","packages."
              ]
          ]
  
      PublishAlreadyPublished vsn ->
        Help.docReport "ALREADY PUBLISHED" Nothing
          ( D.vcat
              [ D.fillSep
                  [ "Version", D.green (D.fromVersion vsn)
                  , "has", "already", "been", "published.", "You", "cannot"
                  , "publish", "it", "again!"
                  ]
              , "Try using the `bump` command:"
              ]
          )
          [ D.dullyellow $ D.indent 4 "elm bump"
          , D.reflow $
              "It computes the version number based on API changes, ensuring\
              \ that no breaking changes end up in PATCH releases!"
          ]
  
      PublishInvalidBump statedVersion latestVersion ->
        Help.docReport "INVALID VERSION" (Just "elm.json")
          ( D.fillSep $
              ["Your","elm.json","says","the","next","version","should","be"
              ,D.red (D.fromVersion statedVersion) <> ","
              ,"but","that","is","not","valid","based","on","the","previously"
              ,"published","versions."
              ]
          )
          [ D.fillSep $
              ["Change","the","version","back","to"
              ,D.green (D.fromVersion latestVersion)
              ,"which","is","the","most","recently","published","version."
              ,"From","there,","have","Elm","bump","the","version","by","running:"
              ]
          , D.indent 4 $ D.green "elm bump"
          , D.reflow $
              "If you want more insight on the API changes Elm detects, you\
              \ can run `elm diff` at this point as well."
          ]
  
      PublishBadBump old new magnitude realNew realMagnitude ->
        Help.docReport "INVALID VERSION" (Just "elm.json")
          (
            D.fillSep $
              ["Your","elm.json","says","the","next","version","should","be"
              ,D.red (D.fromVersion new) <> ","
              ,"indicating","a",D.fromChars (M.toChars magnitude)
              ,"change","to","the","public","API."
              ,"This","does","not","match","the","API","diff","given","by:"
              ]
          )
          [ D.indent 4 $ D.fromChars $
              "elm diff " ++ V.toChars old
  
          , D.fillSep $
              ["This","command","says","this","is","a"
              ,D.fromChars (M.toChars realMagnitude)
              ,"change,","so","the","next","version","should","be"
              ,D.green (D.fromVersion realNew) <> "."
              ,"Double","check","everything","to","make","sure","you"
              ,"are","publishing","what","you","want!"
              ]
          , D.reflow $
              "Also, next time use `elm bump` and I'll figure all this out for you!"
          ]
  
      PublishNoSummary ->
        Help.docReport "NO SUMMARY" (Just "elm.json")
          ( D.fillSep $
              [ "To", "publish", "a", "package,", "your", "elm.json", "must"
              , "have", "a", D.dullyellow "\"summary\"", "field", "that", "gives"
              , "a", "consice", "overview", "of", "your", "project."
              ]
          )
          [ D.reflow $
              "The summary must be less than 80 characters. It should describe\
              \ the concrete use of your package as clearly and as plainly as possible."
          ]
  
      PublishNoExposed ->
        Help.docReport "NO EXPOSED MODULES" (Just "elm.json")
          ( D.fillSep $
              [ "To", "publish", "a", "package,", "the"
              , D.dullyellow "\"exposed-modules\"", "field", "of", "your"
              , "elm.json", "must", "list", "at", "least", "one", "module."
              ]
          )
          [ D.reflow $
              "Which modules do you want users of the package to have access to? Add their\
              \ names to the \"exposed-modules\" list."
          ]
  
      PublishNoReadme ->
        toBadReadmeReport "NO README" $
          "Every published package must have a helpful README.md\
          \ file, but I do not see one in your project."
  
      PublishShortReadme ->
        toBadReadmeReport "SHORT README" $
          "This README.md is too short. Having more details will help\
          \ people assess your package quickly and fairly."
  
      PublishNoLicense ->
        Help.report "NO LICENSE FILE" (Just "LICENSE")
          "By publishing a package you are inviting the Elm community to build\
          \ upon your work. But without knowing your license, we have no idea if\
          \ that is legal!"
          [ D.reflow $
              "Once you pick an OSI approved license from <https://spdx.org/licenses/>,\
              \ you must share that choice in two places. First, the license\
              \ identifier must appear in your elm.json file. Second, the full\
              \ license text must appear in the root of your project in a file\
              \ named LICENSE. Add that file and you will be all set!"
          ]
  
      PublishBuildProblem buildProblem ->
        toBuildProblemReport buildProblem
  
      PublishMissingTag version ->
        let vsn = V.toChars version in
        Help.docReport "NO TAG" Nothing
          ( D.fillSep $
              [ "Packages", "must", "be", "tagged", "in", "git,", "but", "I"
              , "cannot", "find", "a", D.green (D.fromChars vsn), "tag."
              ]
          )
          [ D.vcat
              [ "These tags make it possible to find this specific version on GitHub."
              , "To tag the most recent commit and push it to GitHub, run this:"
              ]
          , D.indent 4 $ D.dullyellow $ D.vcat $ map D.fromChars $
              [ "git tag -a " ++ vsn ++ " -m \"new release\""
              , "git push origin " ++ vsn
              ]
          , "The -m flag is for a helpful message. Try to make it more informative!"
          ]
  
      PublishCannotGetTag version httpError ->
        case httpError of
          Http.BadHttp _ (HTTP.StatusCodeException response _)
            | HTTP.statusCode (HTTP.responseStatus response) == 404 ->
                let vsn = V.toChars version in
                Help.report "NO TAG ON GITHUB" Nothing
                  ("You have version " ++ vsn ++ " tagged locally, but not on GitHub.")
                  [ D.reflow
                      "Run the following command to make this tag available on GitHub:"
                  , D.indent 4 $ D.dullyellow $ D.fromChars $
                      "git push origin " ++ vsn
                  , D.reflow
                      "This will make it possible to find your code online based on the version number."
                  ]
  
          _ ->
            toHttpErrorReport "PROBLEM VERIFYING TAG" httpError
              "I need to check that the version tag is registered on GitHub"
  
      PublishCannotGetTagData version url body ->
        Help.report "PROBLEM VERIFYING TAG" Nothing
          ("I need to check that version " ++ V.toChars version ++ " is tagged on GitHub, so I fetched:")
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
              "I got the data back, but it was not what I was expecting. The response\
              \ body contains " ++ show (BS.length body) ++ " bytes. Here is the "
              ++ if BS.length body <= 76 then "whole thing:" else "beginning:"
          , D.indent 4 $ D.dullyellow $ D.fromChars $
              if BS.length body <= 76
              then BS_UTF8.toString body
              else take 73 (BS_UTF8.toString body) ++ "..."
          , D.reflow $
              "Does this error keep showing up? Maybe there is something weird with your\
              \ internet connection. We have gotten reports that schools, businesses,\
              \ airports, etc. sometimes intercept requests and add things to the body\
              \ or change its contents entirely. Could that be the problem?"
          ]
  
      PublishCannotGetZip httpError ->
        toHttpErrorReport "PROBLEM DOWNLOADING CODE" httpError $
          "I need to check that folks can download and build the source code when they\
          \ install this package"
  
      PublishCannotDecodeZip url ->
        Help.report "PROBLEM DOWNLOADING CODE" Nothing
          "I need to check that folks can download and build the source code when they\
          \ install this package, so I downloaded the code from:"
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
              "I was unable to unzip the archive though. Maybe there is something weird with\
              \ your internet connection. We have gotten reports that schools, businesses,\
              \ airports, etc. sometimes intercept requests and add things to the body or\
              \ change its contents entirely. Could that be the problem?"
          ]
  
      PublishCannotGetDocs old new docsProblem ->
        toDocsProblemReport docsProblem $
          "I need the docs for " ++ V.toChars old ++ " to verify that "
          ++ V.toChars new ++ " really does come next"
  
      PublishCannotRegister httpError ->
        toHttpErrorReport "PROBLEM PUBLISHING PACKAGE" httpError $
          "I need to send information about your package to the package website"
  
      PublishNoGit ->
        Help.report "NO GIT" Nothing
          "I searched your PATH environment variable for `git` and could not\
          \ find it. Is it available through your PATH?"
          [ D.reflow $
              "Who cares about this? Well, I currently use `git` to check if there\
              \ are any local changes in your code. Local changes are a good sign\
              \ that some important improvements have gotten mistagged, so this\
              \ check can be extremely helpful for package authors!"
          , D.toSimpleNote $
              "We plan to do this without the `git` binary in a future release."
          ]
  
      PublishLocalChanges version ->
        let vsn = V.toChars version in
        Help.docReport "LOCAL CHANGES" Nothing
          ( D.fillSep $
              [ "The", "code", "tagged", "as", D.green (D.fromChars vsn), "in"
              , "git", "does", "not", "match", "the", "code", "in", "your"
              , "working", "directory.", "This", "means", "you", "have"
              , "commits", "or", "local", "changes", "that", "are", "not"
              , "going", "to", "be", "published!"
              ]
          )
          [ D.toSimpleNote $
              "If you are sure everything is in order, you can run `git checkout "
              ++ vsn ++ "` and publish your code from there."
          ]
  
      PublishZipBadDetails _ ->
        badZipReport
  
      PublishZipApplication ->
        badZipReport
  
      PublishZipNoExposed ->
        badZipReport
  
      PublishZipBuildProblem _ ->
        badZipReport
  
  
  toBadReadmeReport :: String -> String -> Help.Report
  toBadReadmeReport title summary =
    Help.report title (Just "README.md") summary
      [ D.reflow $
          "When people look at your README, they are wondering:"
      , D.vcat
          [ "  - What does this package even do?"
          , "  - Will it help me solve MY problems?"
          ]
      , D.reflow $
          "So I recommend starting your README with a small example of the\
          \ most common usage scenario. Show people what they can expect if\
          \ they learn more!"
      , D.toSimpleNote $
          "By publishing your package, you are inviting people to invest time in\
          \ understanding your work. Spending an hour on your README to communicate your\
          \ knowledge more clearly can save the community days or weeks of time in\
          \ aggregate, and saving time in aggregate is the whole point of publishing\
          \ packages! People really appreciate it, and it makes the whole ecosystem feel\
          \ nicer!"
      ]
  
  
  badZipReport :: Help.Report
  badZipReport =
    Help.report "PROBLEM VERIFYING PACKAGE" Nothing
      "Before publishing packages, I download the code from GitHub and try to build it\
      \ from scratch. That way I can be more confident that it will work for other\
      \ people too. But I am not able to build it!"
      [ D.reflow $
          "I was just able to build your local copy though. Is there some way the version\
          \ on GitHub could be different?"
      ]
  
  
  
  -- DOCS
  
  
  data DocsProblem
    = DP_Http Http.Error
    | DP_Data String BS.ByteString
    | DP_Cache
  
  
  toDocsProblemReport :: DocsProblem -> String -> Help.Report
  toDocsProblemReport problem context =
    case problem of
      DP_Http httpError ->
        toHttpErrorReport "PROBLEM LOADING DOCS" httpError context
  
      DP_Data url body ->
        Help.report "PROBLEM LOADING DOCS" Nothing (context ++ ", so I fetched:")
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
              "I got the data back, but it was not what I was expecting. The response\
              \ body contains " ++ show (BS.length body) ++ " bytes. Here is the "
              ++ if BS.length body <= 76 then "whole thing:" else "beginning:"
          , D.indent 4 $ D.dullyellow $ D.fromChars $
              if BS.length body <= 76
              then BS_UTF8.toString body
              else take 73 (BS_UTF8.toString body) ++ "..."
          , D.reflow $
              "Does this error keep showing up? Maybe there is something weird with your\
              \ internet connection. We have gotten reports that schools, businesses,\
              \ airports, etc. sometimes intercept requests and add things to the body\
              \ or change its contents entirely. Could that be the problem?"
          ]
  
      DP_Cache ->
        Help.report "PROBLEM LOADING DOCS" Nothing (context ++ ", but the local copy seems to be corrupted.")
          [ D.reflow $
              "I deleted the cached version, so the next run should download a fresh copy of\
              \ the docs. Hopefully that will get you unstuck, but it will not resolve the root\
              \ problem if, for example, a 3rd party editor plugin is modifing cached files\
              \ for some reason."
          ]
  
  
  
  -- INSTALL
  
  
  data Install
    = InstallNoOutline
    | InstallBadOutline Outline
    | InstallBadRegistry RegistryProblem
    | InstallNoArgs FilePath
    | InstallNoOnlineAppSolution Pkg.Name
    | InstallNoOfflineAppSolution Pkg.Name
    | InstallNoOnlinePkgSolution Pkg.Name
    | InstallNoOfflinePkgSolution Pkg.Name
    | InstallHadSolverTrouble Solver
    | InstallUnknownPackageOnline Pkg.Name [Pkg.Name]
    | InstallUnknownPackageOffline Pkg.Name [Pkg.Name]
    | InstallBadDetails Details
  
  
  installToReport :: Install -> Help.Report
  installToReport exit =
    case exit of
      InstallNoOutline ->
        Help.report "NEW PROJECT?" Nothing
          "Are you trying to start a new project? Try this command instead:"
          [ D.indent 4 $ D.green "lamdera init"
          , D.reflow "It will help you get started!"
          ]
  
      InstallBadOutline outline ->
        toOutlineReport outline
  
      InstallBadRegistry problem ->
        toRegistryProblemReport "PROBLEM LOADING PACKAGE LIST" problem $
          "I need the list of published packages to figure out how to install things"
  
      InstallNoArgs elmHome ->
        Help.report "INSTALL WHAT?" Nothing
          "I am expecting commands like:"
          [ D.green $ D.indent 4 $ D.vcat $
              [ "lamdera install elm/http"
              , "lamdera install elm/json"
              , "lamdera install elm/random"
              ]
          , D.toFancyHint
              ["In","JavaScript","folks","run","`npm install`","to","start","projects."
              ,"\"Gotta","download","everything!\"","But","why","download","packages"
              ,"again","and","again?","Instead,","Elm","caches","packages","in"
              ,D.dullyellow (D.fromChars elmHome)
              ,"so","each","one","is","downloaded","and","built","ONCE","on","your","machine."
              ,"Elm","projects","check","that","cache","before","trying","the","internet."
              ,"This","reduces","build","times,","reduces","server","costs,","and","makes","it"
              ,"easier","to","work","offline.","As","a","result"
              ,D.dullcyan "lamdera install","is","only","for","adding","dependencies","to","elm.json,"
              ,"whereas",D.dullcyan "lamdera make","is","in","charge","of","gathering","dependencies"
              ,"and","building","everything.","So","maybe","try",D.green "lamdera make","instead?"
              ]
          ]
  
      InstallNoOnlineAppSolution pkg ->
        Help.report "CANNOT FIND COMPATIBLE VERSION" (Just "elm.json")
          (
            "I cannot find a version of " ++ Pkg.toChars pkg ++ " that is compatible\
            \ with your existing dependencies."
          )
          [ D.reflow $
              "I checked all the published versions. When that failed, I tried to find any\
              \ compatible combination of these packages, even if it meant changing all your\
              \ existing dependencies! That did not work either!"
          , D.reflow $
              "This is most likely to happen when a package is not upgraded yet. Maybe a new\
              \ version of Elm came out recently? Maybe a common package was changed recently?\
              \ Maybe a better package came along, so there was no need to upgrade this one?\
              \ Try asking around https://elm-lang.org/community to learn what might be going on\
              \ with this package."
          , D.toSimpleNote $
              "Whatever the case, please be kind to the relevant package authors! Having\
              \ friendly interactions with users is great motivation, and conversely, getting\
              \ berated by strangers on the internet sucks your soul dry. Furthermore, package\
              \ authors are humans with families, friends, jobs, vacations, responsibilities,\
              \ goals, etc. They face obstacles outside of their technical work you will never\
              \ know about, so please assume the best and try to be patient and supportive!"
          ]
  
      InstallNoOfflineAppSolution pkg ->
        Help.report "CANNOT FIND COMPATIBLE VERSION LOCALLY" (Just "elm.json")
          (
            "I cannot find a version of " ++ Pkg.toChars pkg ++ " that is compatible\
            \ with your existing dependencies."
          )
          [ D.reflow $
              "I was not able to connect to https://package.elm-lang.org/ though, so I was only\
              \ able to look through packages that you have downloaded in the past."
          , D.reflow $
              "Try again later when you have internet!"
          ]
  
      InstallNoOnlinePkgSolution pkg ->
        Help.report "CANNOT FIND COMPATIBLE VERSION" (Just "elm.json")
          (
            "I cannot find a version of " ++ Pkg.toChars pkg ++ " that is compatible\
            \ with your existing constraints."
          )
          [ D.reflow $
              "With applications, I try to broaden the constraints to see if anything works,\
              \ but messing with package constraints is much more delicate business. E.g. making\
              \ your constraints stricter may make it harder for applications to find compatible\
              \ dependencies. So fixing something here may break it for a lot of other people!"
          , D.reflow $
              "So I recommend making an application with the same dependencies as your package.\
              \ See if there is a solution at all. From there it may be easier to figure out\
              \ how to proceed in a way that will disrupt your users as little as possible. And\
              \ the solution may be to help other package authors to get their packages updated,\
              \ or to drop a dependency entirely."
          ]
  
      InstallNoOfflinePkgSolution pkg ->
        Help.report "CANNOT FIND COMPATIBLE VERSION LOCALLY" (Just "elm.json")
          (
            "I cannot find a version of " ++ Pkg.toChars pkg ++ " that is compatible\
            \ with your existing constraints."
          )
          [ D.reflow $
              "I was not able to connect to https://package.elm-lang.org/ though, so I was only\
              \ able to look through packages that you have downloaded in the past."
          , D.reflow $
              "Try again later when you have internet!"
          ]
  
      InstallHadSolverTrouble solver ->
        toSolverReport solver
  
      InstallUnknownPackageOnline pkg suggestions ->
        alternativeImplementationWhen (pkg == Pkg.lamderaCore || pkg == Pkg.lamderaCodecs) (Lamdera.Error.corruptCaches Help.docReport) $
        Help.docReport "UNKNOWN PACKAGE" Nothing
          (
            D.fillSep
              ["I","cannot","find","a","package","named",D.red (D.fromPackage pkg) <> "."]
          )
          [ D.reflow $
              "I looked through https://package.elm-lang.org for packages with similar names\
              \ and found these:"
          , D.indent 4 $ D.dullyellow $ D.vcat $ map D.fromPackage suggestions
          , D.reflow $ "Maybe you want one of these instead?"
          ]
  
      InstallUnknownPackageOffline pkg suggestions ->
        alternativeImplementationWhen (pkg == Pkg.lamderaCore || pkg == Pkg.lamderaCodecs) (Lamdera.Error.corruptCachesOffline Help.docReport) $
        Help.docReport "UNKNOWN PACKAGE" Nothing
          (
            D.fillSep
              ["I","cannot","find","a","package","named",D.red (D.fromPackage pkg) <> "."]
          )
          [ D.reflow $
              "I could not connect to https://package.elm-lang.org though, so new packages may\
              \ have been published since I last updated my local cache of package names."
          , D.reflow $
              "Looking through the locally cached names, the closest ones are:"
          , D.indent 4 $ D.dullyellow $ D.vcat $ map D.fromPackage suggestions
          , D.reflow $ "Maybe you want one of these instead?"
          ]
  
      InstallBadDetails details ->
        toDetailsReport details
  
  
  
  -- SOLVER
  
  
  data Solver
    = SolverBadCacheData Pkg.Name V.Version
    | SolverBadHttpData Pkg.Name V.Version String
    | SolverBadHttp Pkg.Name V.Version Http.Error
  
  
  toSolverReport :: Solver -> Help.Report
  toSolverReport problem =
    case problem of
      SolverBadCacheData pkg vsn ->
        Help.report "PROBLEM SOLVING PACKAGE CONSTRAINTS" Nothing
          (
            "I need the elm.json of " ++ Pkg.toChars pkg ++ " " ++ V.toChars vsn ++ " to\
            \ help me search for a set of compatible packages. I had it cached locally, but\
            \ it looks like the file was corrupted!"
          )
          [ D.reflow $
              "I deleted the cached version, so the next run should download a fresh copy.\
              \ Hopefully that will get you unstuck, but it will not resolve the root\
              \ problem if a 3rd party tool is modifing cached files for some reason."
          ]
  
      SolverBadHttpData pkg vsn url ->
        Help.report "PROBLEM SOLVING PACKAGE CONSTRAINTS" Nothing
          (
            "I need the elm.json of " ++ Pkg.toChars pkg ++ " " ++ V.toChars vsn ++ " to\
            \ help me search for a set of compatible packages, but I ran into corrupted\
            \ information from:"
          )
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
              "Is something weird with your internet connection. We have gotten reports that\
              \ schools, businesses, airports, etc. sometimes intercept requests and add things\
              \ to the body or change its contents entirely. Could that be the problem?"
          ]
  
      SolverBadHttp pkg vsn httpError ->
        toHttpErrorReport "PROBLEM SOLVING PACKAGE CONSTRAINTS" httpError $
          "I need the elm.json of " ++ Pkg.toChars pkg ++ " " ++ V.toChars vsn
          ++ " to help me search for a set of compatible packages"
  
  
  
  -- OUTLINE
  
  
  data Outline
    = OutlineHasBadStructure (Decode.Error OutlineProblem)
    | OutlineHasMissingSrcDirs FilePath [FilePath]
    | OutlineHasDuplicateSrcDirs FilePath FilePath FilePath
    | OutlineNoPkgCore
    | OutlineNoAppCore
    | OutlineNoAppJson
    | OutlineLamderaMissingDeps
  
  
  data OutlineProblem
    = OP_BadType
    | OP_BadPkgName Row Col
    | OP_BadVersion Row Col
    | OP_BadConstraint C.Error
    | OP_BadModuleName Row Col
    | OP_BadModuleHeaderTooLong
    | OP_BadDependencyName Row Col
    | OP_BadLicense Json.String [Json.String]
    | OP_BadSummaryTooLong
    | OP_NoSrcDirs
  
  
  toOutlineReport :: Outline -> Help.Report
  toOutlineReport problem =
    case problem of
      OutlineHasBadStructure decodeError ->
        Json.toReport "elm.json" (Json.FailureToReport toOutlineProblemReport) decodeError $
          Json.ExplicitReason "I ran into a problem with your elm.json file."
  
      OutlineHasMissingSrcDirs dir dirs ->
        case dirs of
          [] ->
            Help.report "MISSING SOURCE DIRECTORY" (Just "elm.json")
              "I need a valid elm.json file, but the \"source-directories\" field lists the following directory:"
              [ D.indent 4 $ D.red $ D.fromChars dir
              , D.reflow $
                  "I cannot find it though. Is it missing? Is there a typo?"
              ]
  
          _:_ ->
            Help.report "MISSING SOURCE DIRECTORIES" (Just "elm.json")
              "I need a valid elm.json file, but the \"source-directories\" field lists the following directories:"
              [ D.indent 4 $ D.vcat $
                  map (D.red . D.fromChars) (dir:dirs)
              , D.reflow $
                  "I cannot find them though. Are they missing? Are there typos?"
              ]
  
      OutlineHasDuplicateSrcDirs canonicalDir dir1 dir2 ->
        if dir1 == dir2 then
          Help.report "REDUNDANT SOURCE DIRECTORIES" (Just "elm.json")
            "I need a valid elm.json file, but the \"source-directories\" field lists the same directory twice:"
            [ D.indent 4 $ D.vcat $
                map (D.red . D.fromChars) [dir1,dir2]
            , D.reflow $
                "Remove one of the entries!"
            ]
        else
          Help.report "REDUNDANT SOURCE DIRECTORIES" (Just "elm.json")
            "I need a valid elm.json file, but the \"source-directories\" field has some redundant directories:"
            [ D.indent 4 $ D.vcat $
                map (D.red . D.fromChars) [dir1,dir2]
            , D.reflow $
                "These are two different ways of refering to the same directory:"
            , D.indent 4 $ D.dullyellow $ D.fromChars canonicalDir
            , D.reflow $
                "Remove one of the redundant entries from your \"source-directories\" field."
            ]
  
      OutlineNoPkgCore ->
        Help.report "MISSING DEPENDENCY" (Just "elm.json")
          "I need to see an \"elm/core\" dependency your elm.json file. The default imports\
          \ of `List` and `Maybe` do not work without it."
          [ D.reflow $
              "If you modified your elm.json by hand, try to change it back! And if you are\
              \ having trouble getting back to a working elm.json, it may be easier to find a\
              \ working package and start fresh with their elm.json file."
          ]
  
      OutlineNoAppCore ->
        Help.report "MISSING DEPENDENCY" (Just "elm.json")
          "I need to see an \"elm/core\" dependency your elm.json file. The default imports\
          \ of `List` and `Maybe` do not work without it."
          [ D.reflow $
              "If you modified your elm.json by hand, try to change it back! And if you are\
              \ having trouble getting back to a working elm.json, it may be easier to delete it\
              \ and use `lamdera init` to start fresh."
          ]
  
      OutlineNoAppJson ->
        Help.report "MISSING DEPENDENCY" (Just "elm.json")
          "I need to see an \"elm/json\" dependency your elm.json file. It helps me handle\
          \ flags and ports."
          [ D.reflow $
              "If you modified your elm.json by hand, try to change it back! And if you are\
              \ having trouble getting back to a working elm.json, it may be easier to delete it\
              \ and use `lamdera init` to start fresh."
          ]
  
      OutlineLamderaMissingDeps ->
        Help.report "MISSING DEPENDENCY" (Just "elm.json")
          "A Lamdera application must have \"lamdera/core\" as a dependency."
          [ D.reflow "You can install it with:"
          , D.indent 4 $ D.green $ "lamdera install lamdera/core"
          , D.reflow "Note: if you're trying to run a normal Elm app, use the elm binary instead."
          ]
  
  
  toOutlineProblemReport :: FilePath -> Code.Source -> Json.Context -> A.Region -> OutlineProblem -> Help.Report
  toOutlineProblemReport path source _ region problem =
    let
      toHighlight row col =
        Just $ A.Region (A.Position row col) (A.Position row col)
  
      toSnippet title highlight pair =
        Help.jsonReport title (Just path) $
          Code.toSnippet source region highlight pair
    in
    case problem of
      OP_BadType ->
        toSnippet "UNEXPECTED TYPE" Nothing
          ( D.reflow $
              "I got stuck while reading your elm.json file. I cannot handle a \"type\" like this:"
          , D.fillSep
              ["Try","changing","the","\"type\"","to"
              ,D.green "\"application\"","or",D.green "\"package\"","instead."
              ]
          )
  
      OP_BadPkgName row col ->
        toSnippet "INVALID PACKAGE NAME" (toHighlight row col)
          ( D.reflow $
              "I got stuck while reading your elm.json file. I ran into trouble with the package name:"
          , D.stack
              [ D.fillSep
                  ["Package","names","are","always","written","as"
                  ,D.green "\"author/project\""
                  ,"so","I","am","expecting","to","see","something","like:"
                  ]
              , D.dullyellow $ D.indent 4 $ D.vcat $
                  [ "\"mdgriffith/elm-ui\""
                  , "\"w0rm/elm-physics\""
                  , "\"Microsoft/elm-json-tree-view\""
                  , "\"FordLabs/elm-star-rating\""
                  , "\"1602/json-schema\""
                  ]
              , D.reflow
                  "The author name should match your GitHub name exactly, and the project name\
                  \ needs to follow these rules:"
              , D.indent 4 $ D.vcat $
                  [ "+--------------------------------------+-----------+-----------+"
                  , "| RULE                                 | BAD       | GOOD      |"
                  , "+--------------------------------------+-----------+-----------+"
                  , "| only lower case, digits, and hyphens | elm-HTTP  | elm-http  |"
                  , "| no leading digits                    | 3D        | elm-3d    |"
                  , "| no non-ASCII characters              | elm-bjørn | elm-bear  |"
                  , "| no underscores                       | elm_ui    | elm-ui    |"
                  , "| no double hyphens                    | elm--hash | elm-hash  |"
                  , "| no starting or ending hyphen         | -elm-tar- | elm-tar   |"
                  , "+--------------------------------------+-----------+-----------+"
                  ]
              , D.toSimpleNote $
                  "These rules only apply to the project name, so you should never need\
                  \ to change your GitHub name!"
              ]
          )
  
      OP_BadVersion row col ->
        toSnippet "PROBLEM WITH VERSION" (toHighlight row col)
          ( D.reflow $
              "I got stuck while reading your elm.json file. I was expecting a version number here:"
          , D.fillSep
              ["I","need","something","like",D.green "\"1.0.0\"","or",D.green "\"2.0.4\""
              ,"that","explicitly","states","all","three","numbers!"
              ]
          )
  
      OP_BadConstraint constraintError ->
        case constraintError of
          C.BadFormat row col ->
            toSnippet "PROBLEM WITH CONSTRAINT" (toHighlight row col)
              ( D.reflow $
                  "I got stuck while reading your elm.json file. I do not understand this version constraint:"
              , D.stack
                  [ D.fillSep
                      ["I","need","something","like",D.green "\"1.0.0 <= v < 2.0.0\""
                      ,"that","explicitly","lists","the","lower","and","upper","bounds."
                      ]
                  , D.toSimpleNote $
                      "The spaces in there are required! Taking them out will confuse me. Adding\
                      \ extra spaces confuses me too. I recommend starting with a valid example\
                      \ and just changing the version numbers."
                  ]
              )
  
          C.InvalidRange before after ->
            if before == after then
              toSnippet "PROBLEM WITH CONSTRAINT" Nothing
                ( D.reflow $
                    "I got stuck while reading your elm.json file. I ran into an invalid version constraint:"
                , D.fillSep
                    ["Elm","checks","that","all","package","APIs","follow","semantic","versioning,"
                    ,"so","it","is","best","to","use","wide","constraints.","I","recommend"
                    ,D.green $ "\"" <> D.fromVersion before <> " <= v < " <> D.fromVersion (V.bumpMajor after) <> "\""
                    ,"since","it","is","guaranteed","that","breaking","API","changes","cannot"
                    ,"happen","in","any","of","the","versions","in","that","range."
                    ]
                )
  
            else
              toSnippet "PROBLEM WITH CONSTRAINT" Nothing
                ( D.reflow $
                    "I got stuck while reading your elm.json file. I ran into an invalid version constraint:"
                , D.fillSep
                    ["Maybe","you","want","something","like"
                    ,D.green $ "\"" <> D.fromVersion before <> " <= v < " <> D.fromVersion (V.bumpMajor before) <> "\""
                    ,"instead?","Elm","checks","that","all","package","APIs","follow","semantic"
                    ,"versioning,","so","it","is","guaranteed","that","breaking","API","changes"
                    ,"cannot","happen","in","any","of","the","versions","in","that","range."
                    ]
                )
  
      OP_BadModuleName row col ->
        toSnippet "PROBLEM WITH MODULE NAME" (toHighlight row col)
          ( D.reflow $
              "I got stuck while reading your elm.json file. I was expecting a module name here:"
          , D.fillSep
              ["I","need","something","like",D.green "\"Html.Events\""
              ,"or",D.green "\"Browser.Navigation\""
              ,"where","each","segment","starts","with","a","capital"
              ,"letter","and","the","segments","are","separated","by","dots."
              ]
          )
  
      OP_BadModuleHeaderTooLong ->
        toSnippet "HEADER TOO LONG" Nothing
          ( D.reflow $
              "I got stuck while reading your elm.json file. This section header is too long:"
          , D.stack
              [ D.fillSep
                  ["I","need","it","to","be"
                  ,D.green "under",D.green "20",D.green "bytes"
                  ,"so","it","renders","nicely","on","the","package","website!"
                  ]
              , D.toSimpleNote
                  "I count the length in bytes, so using non-ASCII characters costs extra.\
                  \ Please report your case at https://github.com/elm/compiler/issues if this seems\
                  \ overly restrictive for your needs."
              ]
          )
  
      OP_BadDependencyName row col ->
        toSnippet "PROBLEM WITH DEPENDENCY NAME" (toHighlight row col)
          ( D.reflow $
              "I got stuck while reading your elm.json file. There is something wrong with this dependency name:"
          , D.stack
              [ D.fillSep
                  ["Package","names","always","include","the","name","of","the","author,"
                  ,"so","I","am","expecting","to","see","dependencies","like"
                  ,D.dullyellow "\"mdgriffith/elm-ui\"","and"
                  ,D.dullyellow "\"Microsoft/elm-json-tree-view\"" <> "."
                  ]
              , D.fillSep $
                  ["I","generally","recommend","finding","the","package","you","want","on"
                  ,"the","package","website,","and","installing","it","with","the"
                  ,D.green "lamdera install","command!"
                  ]
              ]
          )
  
      OP_BadLicense _ suggestions ->
        toSnippet "UNKNOWN LICENSE" Nothing
          ( D.reflow $
              "I got stuck while reading your elm.json file. I do not know about this type of license:"
          ,
            D.stack
              [ D.fillSep
                  ["Elm","packages","generally","use"
                  ,D.green "\"BSD-3-Clause\"","or",D.green "\"MIT\"" <> ","
                  ,"but","I","accept","any","OSI","approved","SPDX","license."
                  ,"Here","some","that","seem","close","to","what","you","wrote:"
                  ]
              , D.indent 4 $ D.dullyellow $ D.vcat $ map (D.fromChars . Json.toChars) suggestions
              , D.reflow $
                  "Check out https://spdx.org/licenses/ for the full list of options."
              ]
          )
  
      OP_BadSummaryTooLong ->
        toSnippet "SUMMARY TOO LONG" Nothing
          ( D.reflow $
              "I got stuck while reading your elm.json file. Your \"summary\" is too long:"
          , D.stack
              [ D.fillSep
                  ["I","need","it","to","be"
                  ,D.green "under",D.green "80",D.green "bytes"
                  ,"so","it","renders","nicely","on","the","package","website!"
                  ]
              , D.toSimpleNote
                  "I count the length in bytes, so using non-ASCII characters costs extra.\
                  \ Please report your case at https://github.com/elm/compiler/issues if this seems\
                  \ overly restrictive for your needs."
              ]
          )
  
      OP_NoSrcDirs ->
        toSnippet "NO SOURCE DIRECTORIES" Nothing
          ( D.reflow $
              "I got stuck while reading your elm.json file. You do not have any \"source-directories\" listed here:"
          , D.fillSep
              ["I","need","something","like",D.green "[\"src\"]"
              ,"so","I","know","where","to","look","for","your","modules!"
              ]
          )
  
  
  
  -- DETAILS
  
  
  data Details
    = DetailsNoSolution (Map.Map Pkg.Name Con.Constraint)
    | DetailsNoOfflineSolution
    | DetailsSolverProblem Solver
    | DetailsBadElmInPkg C.Constraint
    | DetailsBadElmInAppOutline V.Version
    | DetailsHandEditedDependencies
        String -- @LAMDERA addition: reason
    | DetailsBadOutline Outline
    | DetailsCannotGetRegistry RegistryProblem
    | DetailsBadDeps FilePath [DetailsBadDep]
  
  
  data DetailsBadDep
    = BD_BadDownload Pkg.Name V.Version PackageProblem
    | BD_BadBuild Pkg.Name V.Version (Map.Map Pkg.Name V.Version)
  
  
  toDetailsReport :: Details -> Help.Report
  toDetailsReport details =
    case details of
      DetailsNoSolution constraints ->
        Help.report "INCOMPATIBLE DEPENDENCIES" (Just "elm.json")
          "The dependencies in your elm.json are not compatible."
          (
          [ D.fillSep
              ["Did","you","change","them","by","hand?","Try","to","change","it","back!"
              ,"It","is","much","more","reliable","to","add","dependencies","with",D.green "lamdera install" <> "."
              ]
          , D.reflow $
              "Please ask for help on Discord if you try those paths and are still\
              \ having problems!"
          , D.dullyellow $ D.reflow "Note: Sometimes `lamdera reset` can fix this problem by rebuilding caches, so give that a try first."
          ] ++ (if Lamdera.isDebug_
                  then [ D.reflow "Here are the constraints I was trying to solve:"
                       , D.reflow $ show constraints
                       ]
                  else []
               )
          )
  
      DetailsNoOfflineSolution ->
        Help.report "TROUBLE VERIFYING DEPENDENCIES" (Just "elm.json")
          "I could not connect to https://package.elm-lang.org to get the latest list of\
          \ packages, and I was unable to verify your dependencies with the information I\
          \ have cached locally."
          [ D.reflow $
              "Are you able to connect to the internet? These dependencies may work once you\
              \ get access to the registry!"
          , D.toFancyNote
              ["If","you","changed","your","dependencies","by","hand,","try","to","change","them","back!"
              ,"It","is","much","more","reliable","to","add","dependencies","with",D.green "lamdera install" <> "."
              ]
          ]
  
      DetailsSolverProblem solver ->
        toSolverReport solver
  
      DetailsBadElmInPkg constraint ->
        Help.report "ELM VERSION MISMATCH" (Just "elm.json")
          "Your elm.json says this package needs a version of Elm in this range:"
          [ D.indent 4 $ D.dullyellow $ D.fromChars $ C.toChars constraint
          , D.fillSep
              [ "But", "you", "are", "using", "Elm"
              , D.red (D.fromVersion V.compiler)
              , "right", "now."
              ]
          ]
  
      DetailsBadElmInAppOutline version ->
        Help.report "ELM VERSION MISMATCH" (Just "elm.json")
          "Your elm.json says this application needs a different version of Elm."
          [ D.fillSep
              [ "It", "requires"
              , D.green (D.fromVersion version) <> ","
              , "but", "you", "are", "using"
              , D.red (D.fromVersion V.compiler)
              , "right", "now."
              ]
          -- @LAMDERA addition
          , D.reflow $ "Lamdera hint: modify your elm.json to \"elm-version\": \"0.19.1\"."
          ]
  
      DetailsHandEditedDependencies reason ->
        Help.report "ERROR IN DEPENDENCIES" (Just "elm.json")
          "It looks like the dependencies elm.json in were edited by hand (or by a 3rd\
          \ party tool) leaving them in an invalid state."
          [ D.reflow $
              "Reason: " ++ reason
          , D.fillSep
              ["Try","to","change","them","back","to","what","they","were","before!"
              ,"It","is","much","more","reliable","to","add","dependencies","with",D.green "lamdera install" <> "."
              ]
          , D.reflow $
              "Please ask for help on the community forums if you try those paths and are still\
              \ having problems!"
          ]
  
      DetailsBadOutline outline ->
        toOutlineReport outline
  
      DetailsCannotGetRegistry problem ->
        toRegistryProblemReport "PROBLEM LOADING PACKAGE LIST" problem $
          "I need the list of published packages to verify your dependencies"
  
      DetailsBadDeps cacheDir deps ->
        case List.sortOn toBadDepRank deps of
          [] ->
            Help.report "PROBLEM BUILDING DEPENDENCIES" Nothing
              "I am not sure what is going wrong though."
              [ D.reflow $
                  "I would try deleting the " ++ cacheDir ++ " and elm-stuff/ directories, then\
                  \ trying to build again. That will work if some cached files got corrupted\
                  \ somehow."
              , D.reflow $
                  "If that does not work, go to https://elm-lang.org/community and ask for\
                  \ help. This is a weird case!"
              ]
  
          d:_ ->
            case d of
              BD_BadDownload pkg vsn packageProblem ->
                toPackageProblemReport pkg vsn packageProblem
  
              BD_BadBuild pkg vsn fingerprint ->
                -- let
                --   deps_ :: [String]
                --   deps_ =
                --       deps & fmap (\d ->
                --         case d of
                --           -- BD_BadDownload _ _ _ -> "BD_BadDownload"
                --           -- BD_BadBuild _ _ _ -> "BD_BadBuild"
                --
                --           BD_BadDownload pkg version problem ->
                --             "BD_BadDownload"
                --           BD_BadBuild pkg version mapPackages ->
                --             show (Pkg.toChars pkg, V.toChars version, Map.toList mapPackages & fmap (\(p,v) -> (V.toChars v, Pkg.toChars p)))
                --
                --         )
                -- in
                -- debugPass "toDetailsReport" (cacheDir, Pkg.toChars pkg, V.toChars vsn, deps_) $
                Help.report "PROBLEM BUILDING DEPENDENCIES" Nothing
                  "I ran into a compilation error when trying to build the following package:"
                  [ D.indent 4 $ D.red $ D.fromChars $ Pkg.toChars pkg ++ " " ++ V.toChars vsn
                  , D.reflow $
                      "This probably means it has package constraints that are too wide. It may be\
                      \ possible to tweak your elm.json to avoid the root problem as a stopgap. Head\
                      \ over to https://elm-lang.org/community to get help figuring out how to take\
                      \ this path!"
                  , D.toSimpleNote $
                      "To help with the root problem, please report this to the package author along\
                      \ with the following information:"
                  , D.indent 4 $ D.vcat $
                      map (\(p,v) -> D.fromChars $ Pkg.toChars p ++ " " ++ V.toChars v) $
                        Map.toList fingerprint
                  , D.reflow $
                      "If you want to help out even more, try building the package locally. That should\
                      \ give you much more specific information about why this package is failing to\
                      \ build, which will in turn make it easier for the package author to fix it!"
                  , D.dullyellow $ D.reflow "Note: Sometimes `lamdera reset` can fix this problem by rebuilding caches, so give that a try first."
                  ]
  
  
  toBadDepRank :: DetailsBadDep -> Int -- lower is better
  toBadDepRank badDep =
    case badDep of
      BD_BadDownload _ _ _ -> 0
      BD_BadBuild _ _ _ -> 1
  
  
  
  -- PACKAGE PROBLEM
  
  
  data PackageProblem
    = PP_BadEndpointRequest Http.Error
    | PP_BadEndpointContent String
    | PP_BadArchiveRequest Http.Error
    | PP_BadArchiveContent String
    | PP_BadArchiveHash String String String
  
  
  toPackageProblemReport :: Pkg.Name -> V.Version -> PackageProblem -> Help.Report
  toPackageProblemReport pkg vsn problem =
    let
      thePackage =
        Pkg.toChars pkg ++ " " ++ V.toChars vsn
    in
    case problem of
      PP_BadEndpointRequest httpError ->
        toHttpErrorReport "PROBLEM DOWNLOADING PACKAGE" httpError $
          "I need to find the latest download link for " ++ thePackage
  
      PP_BadEndpointContent url ->
        Help.report "PROBLEM DOWNLOADING PACKAGE" Nothing
          (
            "I need to find the latest download link for " ++ thePackage ++ ", but I ran into corrupted information from:"
          )
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
              "Is something weird with your internet connection. We have gotten reports that\
              \ schools, businesses, airports, etc. sometimes intercept requests and add things\
              \ to the body or change its contents entirely. Could that be the problem?"
          ]
  
      PP_BadArchiveRequest httpError ->
        toHttpErrorReport "PROBLEM DOWNLOADING PACKAGE" httpError $
          "I was trying to download the source code for " ++ thePackage
  
      PP_BadArchiveContent url ->
        Help.report "PROBLEM DOWNLOADING PACKAGE" Nothing
          (
            "I downloaded the source code for " ++ thePackage ++ " from:"
          )
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
             "But I was unable to unzip the data. Maybe there is something weird with\
              \ your internet connection. We have gotten reports that schools, businesses,\
              \ airports, etc. sometimes intercept requests and add things to the body or\
              \ change its contents entirely. Could that be the problem?"
          ]
  
      PP_BadArchiveHash url expectedHash actualHash ->
        Help.report "CORRUPT PACKAGE DATA" Nothing
          (
            "I downloaded the source code for " ++ thePackage ++ " from:"
          )
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow "But it looks like the hash of the archive has changed since publication:"
          , D.vcat $ map D.fromChars $
              [ "  Expected: " ++ expectedHash
              , "    Actual: " ++ actualHash
              ]
          , D.reflow $
              "This usually means that the package author moved the version\
              \ tag, so report it to them and see if that is the issue. Folks\
              \ on Elm slack can probably help as well."
          ]
  
  
  
  -- REGISTRY PROBLEM
  
  
  data RegistryProblem
    = RP_Http Http.Error
    | RP_Data String BS.ByteString
  
  
  toRegistryProblemReport :: String -> RegistryProblem -> String -> Help.Report
  toRegistryProblemReport title problem context =
    case problem of
      RP_Http err ->
        toHttpErrorReport title err context
  
      RP_Data url body ->
        Help.report title Nothing (context ++ ", so I fetched:")
          [ D.indent 4 $ D.dullyellow $ D.fromChars url
          , D.reflow $
              "I got the data back, but it was not what I was expecting. The response\
              \ body contains " ++ show (BS.length body) ++ " bytes. Here is the "
              ++ if BS.length body <= 76 then "whole thing:" else "beginning:"
          , D.indent 4 $ D.dullyellow $ D.fromChars $
              if BS.length body <= 76
              then BS_UTF8.toString body
              else take 73 (BS_UTF8.toString body) ++ "..."
          , D.reflow $
              "Does this error keep showing up? Maybe there is something weird with your\
              \ internet connection. We have gotten reports that schools, businesses,\
              \ airports, etc. sometimes intercept requests and add things to the body\
              \ or change its contents entirely. Could that be the problem?"
          ]
  
  
  toHttpErrorReport :: String -> Http.Error -> String -> Help.Report
  toHttpErrorReport title err context =
    let
      toHttpReport intro url details =
        Help.report title Nothing intro $
          D.indent 4 (D.dullyellow (D.fromChars url)) : details
    in
    case err of
      Http.BadUrl url reason ->
        toHttpReport (context ++ ", so I wanted to fetch:") url
          [ D.reflow $ "But my HTTP library is saying this is not a valid URL. It is saying:"
          , D.indent 4 $ D.fromChars reason
          , D.reflow $
              "This may indicate that there is some problem in the compiler, so please open an\
              \ issue at https://github.com/elm/compiler/issues listing your operating system, Elm\
              \ version, the command you ran, the terminal output, and any additional information\
              \ that might help others reproduce the error."
          ]
  
      Http.BadHttp url httpExceptionContent ->
        case httpExceptionContent of
          HTTP.StatusCodeException response body ->
            let
              (HTTP.Status code message) = HTTP.responseStatus response
            in
            toHttpReport (context ++ ", so I tried to fetch:") url
              [ D.fillSep $
                  ["But","it","came","back","as",D.red (D.fromInt code)]
                  ++ map D.fromChars (words (BS_UTF8.toString message))
              , D.indent 4 $ D.reflow $ BS_UTF8.toString body
              , D.reflow $
                  "This may mean some online endpoint changed in an unexpected way, so if does not\
                  \ seem like something on your side is causing this (e.g. firewall) please report\
                  \ this to Discord with your operating system, Elm\
                  \ version, the command you ran, the terminal output, and any additional information\
                  \ that can help others reproduce the error!"
              ]
  
          HTTP.TooManyRedirects responses ->
            toHttpReport (context ++ ", so I tried to fetch:") url
              [ D.reflow $ "But I gave up after following these " ++ show (length responses) ++ " redirects:"
              , D.indent 4 $ D.vcat $ map toRedirectDoc responses
              , D.reflow $
                  "Is it possible that your internet connection intercepts certain requests? That\
                  \ sometimes causes problems for folks in schools, businesses, airports, hotels,\
                  \ and certain countries. Try asking for help locally or in a community forum!"
              ]
  
          otherException ->
            toHttpReport (context ++ ", so I tried to fetch:") url
              [ D.reflow $ "But my HTTP library is giving me the following error message:"
              , D.indent 4 $ D.fromChars (show otherException)
              , D.reflow $
                  "Are you somewhere with a slow internet connection? Or no internet?\
                  \ Does the link I am trying to fetch work in your browser? Maybe the\
                  \ site is down? Does your internet connection have a firewall that\
                  \ blocks certain domains? It is usually something like that!"
              ]
  
      Http.BadMystery url someException ->
        toHttpReport (context ++ ", so I tried to fetch:") url
          [ D.reflow $ "But I ran into something weird! I was able to extract this error message:"
          , D.indent 4 $ D.fromChars (show someException)
          , D.reflow $
              "Is it possible that your internet connection intercepts certain requests? That\
              \ sometimes causes problems for folks in schools, businesses, airports, hotels,\
              \ and certain countries. Try asking for help locally or in a community forum!"
          ]
  
  
  toRedirectDoc :: HTTP.Response body -> D.Doc
  toRedirectDoc response =
    let
      (HTTP.Status code message) = HTTP.responseStatus response
    in
    case List.lookup HTTP.hLocation (HTTP.responseHeaders response) of
      Just loc -> D.red (D.fromInt code) <> " - " <> D.fromChars (BS_UTF8.toString loc)
      Nothing  -> D.red (D.fromInt code) <> " - " <> D.fromChars (BS_UTF8.toString message)
  
  
  
  -- MAKE
  
  
  data Make
    = MakeNoOutline
    | MakeCannotOptimizeAndDebug
    | MakeBadDetails Details
    | MakeAppNeedsFileNames
    | MakePkgNeedsExposing
    | MakeMultipleFilesIntoHtml
    | MakeNoMain
    | MakeNonMainFilesIntoJavaScript ModuleName.Raw [ModuleName.Raw]
    | MakeCannotBuild BuildProblem
    | MakeBadGenerate Generate
  
  
  makeToReport :: Make -> Help.Report
  makeToReport make =
    case make of
      MakeNoOutline ->
        Help.report "NO elm.json FILE" Nothing
          "It looks like you are starting a new Lamdera Elm project. Very exciting! Try running:"
          [ D.indent 4 $ D.green $ "lamdera init"
          , D.reflow $
              "It will help you get set up. It is really simple!"
          ]
  
      MakeCannotOptimizeAndDebug ->
        Help.docReport "CLASHING FLAGS" Nothing
          ( D.fillSep
              ["I","cannot","compile","with",D.red "--optimize","and"
              ,D.red "--debug","at","the","same","time."
              ]
          )
          [ D.reflow
              "I need to take away information to optimize things, and I need to\
              \ add information to add the debugger. It is impossible to do both\
              \ at once though! Pick just one of those flags and it should work!"
          ]
  
      MakeBadDetails detailsProblem ->
        toDetailsReport detailsProblem
  
      MakeAppNeedsFileNames ->
        Help.report "NO INPUT" Nothing
          "What should I make though? I need specific files like:"
          [ D.vcat
              [ D.indent 4 $ D.green "lamdera make src/Main.elm"
              , D.indent 4 $ D.green "lamdera make src/This.elm src/That.elm"
              ]
          , D.reflow $
              "I recommend reading through https://guide.elm-lang.org for guidance on what to\
              \ actually put in those files!"
          ]
  
      MakePkgNeedsExposing ->
        Help.report "NO INPUT" Nothing
          "What should I make though? I need specific files like:"
          [ D.vcat
              [ D.indent 4 $ D.green "lamdera make src/Main.elm"
              , D.indent 4 $ D.green "lamdera make src/This.elm src/That.elm"
              ]
          , D.reflow $
              "You can also entries to the \"exposed-modules\" list in your elm.json file, and\
              \ I will try to compile the relevant files."
          ]
  
      MakeMultipleFilesIntoHtml ->
        Help.report "TOO MANY FILES" Nothing
          (
            "When producing an HTML file, I can only handle one file."
          )
          [ D.fillSep
              ["Switch","to",D.dullyellow "--output=/dev/null","if","you","just","want"
              ,"to","get","compile","errors.","This","skips","the","code","gen","phase,"
              ,"so","it","can","be","a","bit","faster","than","other","options","sometimes."
              ]
          , D.fillSep
              ["Switch","to",D.dullyellow "--output=elm.js","if","you","want","multiple"
              ,"`main`","values","available","in","a","single","JavaScript","file.","Then"
              ,"you","can","make","your","own","customized","HTML","file","that","embeds"
              ,"multiple","Elm","nodes.","The","generated","JavaScript","also","shares"
              ,"dependencies","between","modules,","so","it","should","be","smaller","than"
              ,"compiling","each","module","separately."
              ]
          ]
  
      MakeNoMain ->
        Help.report "NO MAIN" Nothing
          (
            "When producing an HTML file, I require that the given file has a `main` value.\
            \ That way I have something to show on screen!"
          )
          [ D.reflow $
              "Try adding a `main` value to your file? Or if you just want to verify that this\
              \ module compiles, switch to --output=/dev/null to skip the code gen phase\
              \ altogether."
          , D.toSimpleNote $
              "Adding a `main` value can be as brief as adding something like this:"
          , D.vcat
              [ D.fillSep [D.cyan "import","Html"]
              , ""
              , D.fillSep [D.green "main","="]
              , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
              ]
          , D.reflow $
              "From there I can create an HTML file that says \"Hello!\" on screen. I recommend\
              \ looking through https://guide.elm-lang.org for more guidance on how to fill in\
              \ the `main` value."
          ]
  
      MakeNonMainFilesIntoJavaScript m ms ->
        case ms of
          [] ->
            Help.report "NO MAIN" Nothing
              (
                "When producing a JS file, I require that the given file has a `main` value. That\
                \ way Elm." ++ ModuleName.toChars m ++ ".init() is definitely defined in the\
                \ resulting file!"
              )
              [ D.reflow $
                  "Try adding a `main` value to your file? Or if you just want to verify that this\
                  \ module compiles, switch to --output=/dev/null to skip the code gen phase\
                  \ altogether."
              , D.toSimpleNote $
                  "Adding a `main` value can be as brief as adding something like this:"
              , D.vcat
                  [ D.fillSep [D.cyan "import","Html"]
                  , ""
                  , D.fillSep [D.green "main","="]
                  , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
                  ]
              , D.reflow $
                  "Or use https://package.elm-lang.org/packages/elm/core/latest/Platform#worker to\
                  \ make a `main` with no user interface."
              ]
  
          _:_ ->
            Help.report "NO MAIN" Nothing
              (
                "When producing a JS file, I require that given files all have `main` values.\
                \ That way functions like Elm." ++ ModuleName.toChars m ++ ".init() are\
                \ definitely defined in the resulting file. I am missing `main` values in:"
              )
              [ D.indent 4 $ D.red $ D.vcat $ map D.fromName (m:ms)
              , D.reflow $
                  "Try adding a `main` value to them? Or if you just want to verify that these\
                  \ modules compile, switch to --output=/dev/null to skip the code gen phase\
                  \ altogether."
              , D.toSimpleNote $
                  "Adding a `main` value can be as brief as adding something like this:"
              , D.vcat
                  [ D.fillSep [D.cyan "import","Html"]
                  , ""
                  , D.fillSep [D.green "main","="]
                  , D.indent 2 $ D.fillSep [D.cyan "Html" <> ".text",D.dullyellow "\"Hello!\""]
                  ]
              , D.reflow $
                  "Or use https://package.elm-lang.org/packages/elm/core/latest/Platform#worker to\
                  \ make a `main` with no user interface."
              ]
  
      MakeCannotBuild buildProblem ->
        toBuildProblemReport buildProblem
  
      MakeBadGenerate generateProblem ->
        toGenerateReport generateProblem
  
  
  
  -- BUILD PROBLEM
  
  
  data BuildProblem
    = BuildBadModules FilePath Error.Module [Error.Module]
    | BuildProjectProblem BuildProjectProblem
    | BuildLamderaProblem String String [D.Doc]
  
  
  data BuildProjectProblem
    = BP_PathUnknown FilePath
    | BP_WithBadExtension FilePath
    | BP_WithAmbiguousSrcDir FilePath FilePath FilePath
    | BP_MainPathDuplicate FilePath FilePath
    | BP_RootNameDuplicate ModuleName.Raw FilePath FilePath
    | BP_RootNameInvalid FilePath FilePath [String]
    | BP_CannotLoadDependencies
    | BP_Cycle ModuleName.Raw [ModuleName.Raw]
    | BP_MissingExposed (NE.List (ModuleName.Raw, Import.Problem))
  
  
  toBuildProblemReport :: BuildProblem -> Help.Report
  toBuildProblemReport problem =
    case problem of
      BuildBadModules root e es ->
        Help.compilerReport root e es
  
      BuildProjectProblem projectProblem ->
        toProjectProblemReport projectProblem
  
      BuildLamderaProblem title topline ddoc ->
        Help.report title Nothing topline ddoc
  
  toProjectProblemReport :: BuildProjectProblem -> Help.Report
  toProjectProblemReport projectProblem =
    case projectProblem of
      BP_PathUnknown path ->
        Help.report "FILE NOT FOUND" Nothing
          "I cannot find this file:"
          [ D.indent 4 $ D.red $ D.fromChars path
          , D.reflow $ "Is there a typo?"
          , D.toSimpleNote $
              "If you are just getting started, try working through the examples in the\
              \ official guide https://guide.elm-lang.org to get an idea of the kinds of things\
              \ that typically go in a src/Main.elm file."
          ]
  
      BP_WithBadExtension path ->
        Help.report "UNEXPECTED FILE EXTENSION" Nothing
          "I can only compile Elm files (with a .elm extension) but you want me to compile:"
          [ D.indent 4 $ D.red $ D.fromChars path
          , D.reflow $ "Is there a typo? Can the file extension be changed?"
          ]
  
      BP_WithAmbiguousSrcDir path srcDir1 srcDir2 ->
        Help.report "CONFUSING FILE" Nothing
          "I am getting confused when I try to compile this file:"
          [ D.indent 4 $ D.red $ D.fromChars path
          , D.reflow $
              "I always check if files appear in any of the \"source-directories\" listed in\
              \ your elm.json to see if there might be some cached information about them. That\
              \ can help me compile faster! But in this case, it looks like this file may be in\
              \ either of these directories:"
          , D.indent 4 $ D.red $ D.vcat $ map D.fromChars [srcDir1,srcDir2]
          , D.reflow $
              "Try to make it so no source directory contains another source directory!"
          ]
  
      BP_MainPathDuplicate path1 path2 ->
        Help.report "CONFUSING FILES" Nothing
          "You are telling me to compile these two files:"
          [ D.indent 4 $ D.red $ D.vcat $ map D.fromChars [ path1, path2 ]
          , D.reflow $
              if path1 == path2 then
                "Why are you telling me twice? Is something weird going on with a script?\
                \ I figured I would let you know about it just in case something is wrong.\
                \ Only list it once and you should be all set!"
              else
                "But seem to be the same file though... It makes me think something tricky is\
                \ going on with symlinks in your project, so I figured I would let you know\
                \ about it just in case. Remove one of these files from your command to get\
                \ unstuck!"
          ]
  
      BP_RootNameDuplicate name outsidePath otherPath ->
        Help.report "MODULE NAME CLASH" Nothing
          "These two files are causing a module name clash:"
          [ D.indent 4 $ D.red $ D.vcat $ map D.fromChars [ outsidePath, otherPath ]
          , D.reflow $
              "They both say `module " ++ ModuleName.toChars name ++ " exposing (..)` up\
              \ at the top, but they cannot have the same name!"
          , D.reflow $
              "Try changing to a different module name in one of them!"
          ]
  
      BP_RootNameInvalid givenPath srcDir _ ->
        Help.report "UNEXPECTED FILE NAME" Nothing
          "I am having trouble with this file name:"
          [ D.indent 4 $ D.red $ D.fromChars givenPath
          , D.reflow $
              "I found it in your " ++ FP.addTrailingPathSeparator srcDir ++ " directory\
              \ which is good, but I expect all of the files in there to use the following\
              \ module naming convention:"
          , toModuleNameConventionTable srcDir [ "Main", "HomePage", "Http.Helpers" ]
          , D.reflow $
              "Notice that the names always start with capital letters! Can you make your file\
              \ use this naming convention?"
          , D.toSimpleNote $
              "Having a strict naming convention like this makes it a lot easier to find\
              \ things in large projects. If you see a module imported, you know where to look\
              \ for the corresponding file every time!"
          ]
  
      BP_CannotLoadDependencies ->
        corruptCacheReport
  
      BP_Cycle name names ->
        Help.report "IMPORT CYCLE" Nothing
          "Your module imports form a cycle:"
          [ D.cycle 4 name names
          , D.reflow $
              "Learn more about why this is disallowed and how to break cycles here:"
              ++ D.makeLink "import-cycles"
          ]
  
      BP_MissingExposed (NE.List (name, problem) _) ->
        case problem of
          Import.NotFound ->
            Help.report "MISSING MODULE" (Just "elm.json")
              "The  \"exposed-modules\" of your elm.json lists the following module:"
              [ D.indent 4 $ D.red $ D.fromName name
              , D.reflow $
                  "But I cannot find it in your src/ directory. Is there a typo? Was it renamed?"
              ]
  
          Import.Ambiguous _ _ pkg _ ->
            Help.report "AMBIGUOUS MODULE NAME" (Just "elm.json")
              "The  \"exposed-modules\" of your elm.json lists the following module:"
              [ D.indent 4 $ D.red $ D.fromName name
              , D.reflow $
                  "But a module from " ++ Pkg.toChars pkg ++ " already uses that name. Try\
                  \ choosing a different name for your local file."
              ]
  
          Import.AmbiguousLocal path1 path2 paths ->
            Help.report "AMBIGUOUS MODULE NAME" (Just "elm.json")
              "The  \"exposed-modules\" of your elm.json lists the following module:"
              [ D.indent 4 $ D.red $ D.fromName name
              , D.reflow $
                  "But I found multiple files with that name:"
              , D.dullyellow $ D.indent 4 $ D.vcat $
                  map D.fromChars (path1:path2:paths)
              , D.reflow $
                  "Change the module names to be distinct!"
              ]
  
          Import.AmbiguousForeign _ _ _ ->
            Help.report "MISSING MODULE" (Just "elm.json")
              "The  \"exposed-modules\" of your elm.json lists the following module:"
              [ D.indent 4 $ D.red $ D.fromName name
              , D.reflow $
                  "But I cannot find it in your src/ directory. Is there a typo? Was it renamed?"
              , D.toSimpleNote $
                  "It is not possible to \"re-export\" modules from other packages. You can only\
                  \ expose modules that you define in your own code."
              ]
  
  
  toModuleNameConventionTable :: FilePath -> [String] -> D.Doc
  toModuleNameConventionTable srcDir names =
    let
      toPair name =
        ( name
        , srcDir </> map (\c -> if c == '.' then FP.pathSeparator else c) name <.> "elm"
        )
  
      namePairs = map toPair names
      nameWidth = maximum (11 : map (length . fst) namePairs)
      pathWidth = maximum ( 9 : map (length . snd) namePairs)
  
      padded width str =
        str ++ replicate (width - length str) ' '
  
      toRow (name, path) =
        D.fromChars $
          "| " ++ padded nameWidth name ++ " | " ++ padded pathWidth path ++ " |"
  
      bar =
        D.fromChars $
          "+-" ++ replicate nameWidth '-' ++ "-+-" ++ replicate pathWidth '-' ++ "-+"
    in
    D.indent 4 $ D.vcat $
      [ bar, toRow ("Module Name", "File Path"), bar ] ++ map toRow namePairs ++ [ bar ]
  
  
  
  -- GENERATE
  
  
  data Generate
    = GenerateCannotLoadArtifacts
    | GenerateCannotOptimizeDebugValues ModuleName.Raw [ModuleName.Raw]
  
  
  toGenerateReport :: Generate -> Help.Report
  toGenerateReport problem =
    case problem of
      GenerateCannotLoadArtifacts ->
        corruptCacheReport
  
      GenerateCannotOptimizeDebugValues m ms ->
        Help.report "DEBUG REMNANTS" Nothing
          "There are uses of the `Debug` module in the following modules:"
          [ D.indent 4 $ D.red $ D.vcat $ map (D.fromChars . ModuleName.toChars) (m:ms)
          , D.reflow "But the --optimize flag only works if all `Debug` functions are removed!"
          , D.toSimpleNote $
              "The issue is that --optimize strips out info needed by `Debug` functions.\
              \ Here are two examples:"
          , D.indent 4 $ D.reflow $
              "(1) It shortens record field names. This makes the generated JavaScript\
              \ smaller, but `Debug.toString` cannot know the real field names anymore."
          , D.indent 4 $ D.reflow $
              "(2) Values like `type Height = Height Float` are unboxed. This reduces\
              \ allocation, but it also means that `Debug.toString` cannot tell if it is\
              \ looking at a `Height` or `Float` value."
          , D.reflow $
              "There are a few other cases like that, and it will be much worse once we start\
              \ inlining code. That optimization could move `Debug.log` and `Debug.todo` calls,\
              \ resulting in unpredictable behavior. I hope that clarifies why this restriction\
              \ exists!"
          ]
  
  
  
  -- CORRUPT CACHE
  
  
  corruptCacheReport :: Help.Report
  corruptCacheReport =
    Help.report "CORRUPT CACHE" Nothing
      "It looks like some of the information cached in elm-stuff/ has been corrupted."
      [ D.reflow $
          "Try deleting your elm-stuff/ directory to get unstuck."
      , D.toSimpleNote $
          "This almost certainly means that a 3rd party tool (or editor plugin) is\
          \ causing problems your the elm-stuff/ directory. Try disabling 3rd party tools\
          \ one by one until you figure out which it is!"
      ]
  
  
  
  -- REACTOR
  
  
  data Reactor
    = ReactorNoOutline
    | ReactorBadDetails Details
    | ReactorBadBuild BuildProblem
    | ReactorBadGenerate Generate
  
  
  reactorToReport :: Reactor -> Help.Report
  reactorToReport problem =
    case problem of
      ReactorNoOutline ->
        Help.report "NEW PROJECT?" Nothing
          "Are you trying to start a new project? Try this command in the terminal:"
          [ D.indent 4 $ D.green "lamdera init"
          , D.reflow "It will help you get started!"
          ]
  
      ReactorBadDetails details ->
        toDetailsReport details
  
      ReactorBadBuild buildProblem ->
        toBuildProblemReport buildProblem
  
      ReactorBadGenerate generate ->
        toGenerateReport generate
  
  
  
  -- REPL
  
  
  data Repl
    = ReplBadDetails Details
    | ReplBadInput BS.ByteString Error.Error
    | ReplBadLocalDeps FilePath Error.Module [Error.Module]
    | ReplProjectProblem BuildProjectProblem
    | ReplBadGenerate Generate
    | ReplBadCache
    | ReplBlocked
  
  
  replToReport :: Repl -> Help.Report
  replToReport problem =
    case problem of
      ReplBadDetails details ->
        toDetailsReport details
  
      ReplBadInput source err ->
        Help.compilerReport "/" (Error.Module N.replModule "REPL" File.zeroTime source err) []
  
      ReplBadLocalDeps root e es ->
        Help.compilerReport root e es
  
      ReplProjectProblem projectProblem ->
        toProjectProblemReport projectProblem
  
      ReplBadGenerate generate ->
        toGenerateReport generate
  
      ReplBadCache ->
        corruptCacheReport
  
      ReplBlocked ->
        corruptCacheReport
  