import           Control.Concurrent (setNumCapabilities)
import           Crypto.Hash        (hashWith, SHA256 (..), Digest)
import           Control.Monad      (replicateM, join, (>=>))
import           Control.Monad.Par  (runPar, get, spawnP)
import           Data.ByteString    (pack)
import           Data.List.Split    (chunksOf)
import           GHC.Conc           (getNumProcessors)
import           Text.Printf        (printf)

hashedValues :: [Digest SHA256]
hashedValues = read <$>
  [ "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"
  , "74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f"
  , "1115dd800feaacefdf481f1f9070374a2a81e27880f187396db67958b207cbad" ]

bruteForce :: Int -> [(String, String)]
bruteForce n = runPar $ join <$> 
  (mapM (spawnP . foldr findMatch []) >=> mapM get) chunks
  where
    chunks = chunksOf (26^5 `div` n) $ replicateM 5 [97..122]
    findMatch s accum
      | hashed `elem` hashedValues = (show hashed, show bStr): accum
      | otherwise = accum
      where
        bStr = pack s
        hashed = hashWith SHA256 bStr

main :: IO ()
main = do
  cpus <- getNumProcessors
  setNumCapabilities cpus
  printf "Using%d cores\n" cpus
  mapM_ (uncurry (printf "%s ->%s\n")) (bruteForce cpus)