module Days.Day07 where

import AOCUtil
import Data.Char
import Data.List
import GHC.Utils.Misc

runA :: IO ()
runA = interactF "data/day07.txt" (solve)

runB :: IO ()
runB = interactF "data/day07.txt" (solveB)

solve :: String -> String
solve s = show . sum . filter (< 100000) . map (getDirectorySize fl) . getDirectories $ fl
  where
    fl = generateFileList [] . lines $ s

solveB :: String -> String
solveB s = show . head . sort . filter (>= toFree fl) . map (getDirectorySize fl) . getDirectories $ fl
  where
    fl = generateFileList [] . lines $ s

type File = ([String], Int) -- Path (Reversed) including Filename, Size

generateFileList :: [String] -> [String] -> [File] -- current dir (reversed), list of commands
generateFileList _ [] = []
generateFileList dir (c : cs)
  | isPrefixOf "$ cd .." c = generateFileList (tail dir) cs
  | isPrefixOf "$ cd" c = generateFileList ((last $ words c) : dir) cs
  -- \| isPrefixOf "$ ls" c = generateFileList dir cs
  | isDigit $ head c = (((last . words $ c) : dir), read . last . init . words $ c) : (generateFileList dir cs)
  | otherwise = generateFileList dir cs

type Dir = [String]

getDirectories :: [File] -> [Dir]
getDirectories = nub . sort . concatMap (tails . tail . fst)

getDirectorySize :: [File] -> Dir -> Int
getDirectorySize fs d = sum . map snd . filter (isSuffixOf d . fst) $ fs

toFree :: [File] -> Int
toFree = (flip (-) 40000000) . (flip getDirectorySize) ["/"]
