import Data.Char
import Data.List
import Data.List.Split

main :: IO ()
main = do
  input <- map (unwords . lines) . splitOn "\n\n" <$> readFile "input"
  print $ day4 input validateA
  print $ day4 input validateB

day4 :: [String] -> ([[String]] -> Bool) -> Int
day4 input vldt = length $ filter vldt $ map (map (splitOn ":") . words) input

validateA :: [[String]] -> Bool
validateA =
  null . (\\) ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"] . map head

validateB :: [[String]] -> Bool
validateB input = validateA input && all val input
  where
    val (x:xs)
      | "byr" <- x = pars >= 1920 && pars <= 2002
      | "iyr" <- x = pars >= 2010 && pars <= 2020
      | "eyr" <- x = pars >= 2020 && pars <= 2030
      | "hgt" <- x =
        case partition isDigit b of
          (y, "cm") -> read y >= 150 && read y <= 193
          (y, "in") -> read y >= 59 && read y <= 76
          _ -> False
      | "hcl" <- x =
        (head b == '#') &&
        all (`elem` (['0' .. '9'] `union` ['a' .. 'f'])) (tail b) &&
        (length b == 7)
      | "ecl" <- x = b `elem` ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
      | "pid" <- x = length b == 9 && null (dropWhile isDigit b)
      | "cid" <- x = True
      | _ <- x = False
      where
        pars = read b
        b = head xs
