module FortyTwo.Prompts.Password (password) where

import System.Console.ANSI (cursorBackward, clearFromCursorToScreenEnd, setCursorColumn, clearFromCursorToLineEnd)
import Control.Monad (unless)
import FortyTwo.Renderers.Password (renderPassword, hideLetters)
import FortyTwo.Renderers.Question (renderQuestion)
import FortyTwo.Constants (emptyString, enterKey, delKey)
import FortyTwo.Utils

-- | Ask a user password
-- password "What your secret password?"
password :: String -> IO String
password question = do
  putStrLn emptyString
  renderQuestion question emptyString emptyString
  putStr " "
  flush
  noBuffering
  answer <- loop emptyString
  restoreBuffering
  -- for the password prompt we need to clear the prompt a bit differently
  setCursorColumn 0
  clearFromCursorToLineEnd
  renderQuestion question emptyString $ hideLetters answer
  return answer

-- | Loop to let the users select an single option
loop :: String -> IO String
loop pass = do
  noEcho
  renderPassword pass
  key <- getKey

  -- Cancel part of the password avoiding to cancel the question as well
  -- the password and the question are located on the same line
  unless (null pass) $ do
    cursorBackward $ length pass
    clearFromCursorToScreenEnd

  -- Try to filter the control keys
  res <- handleEvent pass (if length key > 1 then emptyString else key)
  restoreEcho
  return res

-- | Handle a user event
handleEvent :: String -> String -> IO String
handleEvent pass key
  | key == enterKey = return pass
  | key == delKey =
    if null pass then return loop emptyString pass
    else return loop emptyString (init pass)
  | otherwise = loop $ pass ++ key