-- | Ensure GHC is installed and provide the PATHs to add if necessary
ensureGHC :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)
          => SetupOpts
          -> m (Maybe [FilePath])
ensureGHC sopts = do
    -- Check the available GHCs
    menv0 <- getMinimalEnvOverride

    msystem <-
        if soptsUseSystem sopts
            then getSystemGHC menv0
            else return Nothing

    Platform expectedArch _ <- asks getPlatform

    let needLocal = case msystem of
            Nothing -> True
            Just _ | soptsSkipGhcCheck sopts -> False
            Just (system, arch) ->
                -- we allow a newer version of GHC within the same major series
                getMajorVersion system /= getMajorVersion expected ||
                expected > system ||
                arch /= expectedArch

    -- If we need to install a GHC, try to do so
    mpaths <- if needLocal
        then do
            config <- asks getConfig
            let tools =
                    case configPlatform config of
                        Platform _ os | isWindows os ->
                              ($(mkPackageName "ghc"), Just expected)
                            : (if soptsSkipMsys sopts
                                then []
                                else [($(mkPackageName "git"), Nothing)])
                        _ ->
                            [ ($(mkPackageName "ghc"), Just expected)
                            ]

            -- Avoid having to load it twice
            siRef <- liftIO $ newIORef Nothing
            manager <- asks getHttpManager
            let getSetupInfo' = liftIO $ do
                    msi <- readIORef siRef
                    case msi of
                        Just si -> return si
                        Nothing -> do
                            si <- getSetupInfo manager
                            writeIORef siRef $ Just si
                            return si

            installed <- runReaderT listInstalled config
            idents <- mapM (ensureTool menv0 sopts installed getSetupInfo' msystem) tools
            paths <- runReaderT (mapM binDirs $ catMaybes idents) config
            return $ Just $ map toFilePathNoTrailingSlash $ concat paths
        else return Nothing

    when (soptsSanityCheck sopts) $ do
        menv <-
            case mpaths of
                Nothing -> return menv0
                Just paths -> do
                    config <- asks getConfig
                    let m0 = unEnvOverride menv0
                        path0 = Map.lookup "PATH" m0
                        path = augmentPath paths path0
                        m = Map.insert "PATH" path m0
                    mkEnvOverride (configPlatform config) m
        sanityCheck menv

    return mpaths
  where
    expected = soptsExpected sopts

-- | Get the major version of the system GHC, if available
ensureGHC :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)
          => SetupOpts
          -> m (Maybe [FilePath])
ensureGHC sopts = do
    -- Check the available GHCs
    menv0 <- getMinimalEnvOverride

    msystem <-
        if soptsUseSystem sopts
            then getSystemGHC menv0
            else return Nothing

    Platform expectedArch _ <- asks getPlatform

    let needLocal = case msystem of
            Nothing -> True
            Just _ | soptsSkipGhcCheck sopts -> False
            Just (system, arch) ->
                -- we allow a newer version of GHC within the same major series
                getMajorVersion system /= getMajorVersion expected ||
                expected > system ||
                arch /= expectedArch

    -- If we need to install a GHC, try to do so
    mpaths <- if needLocal
        then do
            config <- asks getConfig
            let tools =
                    case configPlatform config of
                        Platform _ os | isWindows os ->
                              ($(mkPackageName "ghc"), Just expected)
                            : (if soptsSkipMsys sopts
                                then []
                                else [($(mkPackageName "git"), Nothing)])
                        _ ->
                            [ ($(mkPackageName "ghc"), Just expected)
                            ]

            -- Avoid having to load it twice
            siRef <- liftIO $ newIORef Nothing
            manager <- asks getHttpManager
            let getSetupInfo' = liftIO $ do
                    msi <- readIORef siRef
                    case msi of
                        Just si -> return si
                        Nothing -> do
                            si <- getSetupInfo manager
                            writeIORef siRef $ Just si
                            return si

            installed <- runReaderT listInstalled config
            idents <- mapM (ensureTool menv0 sopts installed getSetupInfo' msystem) tools
            paths <- runReaderT (mapM binDirs $ catMaybes idents) config
            return $ Just $ map toFilePathNoTrailingSlash $ concat paths
        else return Nothing

    when (soptsSanityCheck sopts) $ do
        menv <-
            case mpaths of
                Nothing -> return menv0
                Just paths -> do
                    config <- asks getConfig
                    let m0 = unEnvOverride menv0
                        path0 = Map.lookup "PATH" m0
                        path = augmentPath paths path0
                        m = Map.insert "PATH" path m0
                    mkEnvOverride (configPlatform config) m
        sanityCheck menv

    return mpaths
  where
    expected = soptsExpected sopts

-- | Get the major version of the system GHC, if available
ensureGHC sopts = do
    -- Check the available GHCs
    menv0 <- getMinimalEnvOverride

    msystem <-
        if soptsUseSystem sopts
            then getSystemGHC menv0
            else return Nothing

    Platform expectedArch _ <- asks getPlatform

    let needLocal = case msystem of
            Nothing -> True
            Just _ | soptsSkipGhcCheck sopts -> False
            Just (system, arch) ->
                -- we allow a newer version of GHC within the same major series
                getMajorVersion system /= getMajorVersion expected ||
                expected > system ||
                arch /= expectedArch

    -- If we need to install a GHC, try to do so
    mpaths <- if needLocal
        then do
            config <- asks getConfig
            let tools =
                    case configPlatform config of
                        Platform _ os | isWindows os ->
                              ($(mkPackageName "ghc"), Just expected)
                            : (if soptsSkipMsys sopts
                                then []
                                else [($(mkPackageName "git"), Nothing)])
                        _ ->
                            [ ($(mkPackageName "ghc"), Just expected)
                            ]

            -- Avoid having to load it twice
            siRef <- liftIO $ newIORef Nothing
            manager <- asks getHttpManager
            let getSetupInfo' = liftIO $ do
                    msi <- readIORef siRef
                    case msi of
                        Just si -> return si
                        Nothing -> do
                            si <- getSetupInfo manager
                            writeIORef siRef $ Just si
                            return si

            installed <- runReaderT listInstalled config
            idents <- mapM (ensureTool menv0 sopts installed getSetupInfo' msystem) tools
            paths <- runReaderT (mapM binDirs $ catMaybes idents) config
            return $ Just $ map toFilePathNoTrailingSlash $ concat paths
        else return Nothing

    when (soptsSanityCheck sopts) $ do
        menv <-
            case mpaths of
                Nothing -> return menv0
                Just paths -> do
                    config <- asks getConfig
                    let m0 = unEnvOverride menv0
                        path0 = Map.lookup "PATH" m0
                        path = augmentPath paths path0
                        m = Map.insert "PATH" path m0
                    mkEnvOverride (configPlatform config) m
        sanityCheck menv

    return mpaths
  where
    expected = soptsExpected sopts

-- | Get the major version of the system GHC, if available