-- | Extract the list of ENV var from a 'Options.Applicative.Parser'
varFromParser
    :: Parser a             -- Target parser
    -> [(String, ArgType)]
varFromParser parser =
    foldParse (helpToByteString help)
  where
    -- Here is the little trick, we leverage the parserFailure which displays
    -- a usage with all possible arguments and flags and from this usage,
    -- we capture all arguments and flags as tuple (String, ArgType)
    (help, _, _) =
        let
            pInfo = info parser mempty
        in
            execFailure (parserFailure Parser.defaultPrefs pInfo ShowHelpText mempty) ""

    -- NOTE: 'fromJust' is safe here as there's always a usage
    helpToByteString :: ParserHelp -> ByteString
    helpToByteString =
        B8.pack . show . fromJust . unChunk . helpUsage

    -- | Convert a string argument to its corresponding ENV var
    argToVar :: String -> (String, ArgType)
    argToVar arg = case elemIndex ' ' arg of
        Nothing -> (kToS (drop 2 arg), Flag)
        Just i  -> (kToS (drop 2 (take i arg)), Arg)

    foldParse :: ByteString -> [(String, ArgType)]
    foldParse =
        rights
            . fmap (fmap (argToVar . B8.unpack) . parseOnly capture)
            . B8.lines

    capture :: Atto.Internal.Parser ByteString ByteString
    capture =
        (skipWhile (/= '[') *> string "[" *> takeWhile (/= ']') <* string "]")
        <|>
        (do
            skipSpace
            _ <- string "--"
            str <- takeWhile (not . Char.isSpace)
            marg <- fmap (fromMaybe "") . optional $ do
                _ <- string " "
                str2 <- takeWhile (not . Char.isSpace)
                pure (" " <> str2)
            pure ("--" <> str <> marg)
        )



-- | Run a parser from environment variables rather than command-line arguments
varFromParser
    :: Parser a             -- Target parser
    -> [(String, ArgType)]
varFromParser parser =
    foldParse (helpToByteString help)
  where
    -- Here is the little trick, we leverage the parserFailure which displays
    -- a usage with all possible arguments and flags and from this usage,
    -- we capture all arguments and flags as tuple (String, ArgType)
    (help, _, _) =
        let
            pInfo = info parser mempty
        in
            execFailure (parserFailure Parser.defaultPrefs pInfo ShowHelpText mempty) ""

    -- NOTE: 'fromJust' is safe here as there's always a usage
    helpToByteString :: ParserHelp -> ByteString
    helpToByteString =
        B8.pack . show . fromJust . unChunk . helpUsage

    -- | Convert a string argument to its corresponding ENV var
    argToVar :: String -> (String, ArgType)
    argToVar arg = case elemIndex ' ' arg of
        Nothing -> (kToS (drop 2 arg), Flag)
        Just i  -> (kToS (drop 2 (take i arg)), Arg)

    foldParse :: ByteString -> [(String, ArgType)]
    foldParse =
        rights
            . fmap (fmap (argToVar . B8.unpack) . parseOnly capture)
            . B8.lines

    capture :: Atto.Internal.Parser ByteString ByteString
    capture =
        (skipWhile (/= '[') *> string "[" *> takeWhile (/= ']') <* string "]")
        <|>
        (do
            skipSpace
            _ <- string "--"
            str <- takeWhile (not . Char.isSpace)
            marg <- fmap (fromMaybe "") . optional $ do
                _ <- string " "
                str2 <- takeWhile (not . Char.isSpace)
                pure (" " <> str2)
            pure ("--" <> str <> marg)
        )



-- | Run a parser from environment variables rather than command-line arguments
varFromParser parser =
    foldParse (helpToByteString help)
  where
    -- Here is the little trick, we leverage the parserFailure which displays
    -- a usage with all possible arguments and flags and from this usage,
    -- we capture all arguments and flags as tuple (String, ArgType)
    (help, _, _) =
        let
            pInfo = info parser mempty
        in
            execFailure (parserFailure Parser.defaultPrefs pInfo ShowHelpText mempty) ""

    -- NOTE: 'fromJust' is safe here as there's always a usage
    helpToByteString :: ParserHelp -> ByteString
    helpToByteString =
        B8.pack . show . fromJust . unChunk . helpUsage

    -- | Convert a string argument to its corresponding ENV var
    argToVar :: String -> (String, ArgType)
    argToVar arg = case elemIndex ' ' arg of
        Nothing -> (kToS (drop 2 arg), Flag)
        Just i  -> (kToS (drop 2 (take i arg)), Arg)

    foldParse :: ByteString -> [(String, ArgType)]
    foldParse =
        rights
            . fmap (fmap (argToVar . B8.unpack) . parseOnly capture)
            . B8.lines

    capture :: Atto.Internal.Parser ByteString ByteString
    capture =
        (skipWhile (/= '[') *> string "[" *> takeWhile (/= ']') <* string "]")
        <|>
        (do
            skipSpace
            _ <- string "--"
            str <- takeWhile (not . Char.isSpace)
            marg <- fmap (fromMaybe "") . optional $ do
                _ <- string " "
                str2 <- takeWhile (not . Char.isSpace)
                pure (" " <> str2)
            pure ("--" <> str <> marg)
        )



-- | Run a parser from environment variables rather than command-line arguments