import Data.Char
import Data.Function (on)
import Data.List

data Hand =
  C Int Int Int Int Int
  deriving (Eq, Show)

instance Ord Hand where
  compare x y =
    let r = (compare `on` handType) x y
        f (C x1 x2 x3 x4 x5) = (x1, x2, x3, x4, x5)
     in case r of
          EQ -> (compare `on` f) x y
          _ -> r

handType :: Hand -> Int
handType (C x1 x2 x3 x4 x5) =
  case cList of
    [5] -> 7
    [1, 4] -> 6 + signum j
    [2, 3] -> 4 + 3 * signum j
    [1, 1, 3] -> 3 + 3 * signum j
    [1, 2, 2] -> 2 + 2 * j
    [1, 1, 1, 2] -> 1 + 2 * signum j
    _ -> 0 + signum j
  where
    cList = sort $ map length $ group sList
    sList = sort [x1, x2, x3, x4, x5]
    j = length (filter (== 1) sList)

main :: IO ()
main = do
  input <- readFile "input"
  print $ day07 (parse False input)
  print $ day07 (parse True input)

day07 :: [(Hand, Int)] -> Int
day07 = sum . zipWith (*) [1 ..] . map snd . sort

parse :: Bool -> String -> [(Hand, Int)]
parse p2 = map (f . words) . lines
  where
    f [x, y] = (parseHand x, read y)
    f x = error ("parse: Malformed input: " ++ show x)
    parseHand = g . map (digitToCard p2)
    g [x1, x2, x3, x4, x5] = C x1 x2 x3 x4 x5
    g x = error ("parseHand: Malformed input: " ++ show x)

digitToCard :: Bool -> Char -> Int
digitToCard p2 x
  | isDigit x = digitToInt x
  | x == 'J' && p2 = 1
  | x == 'T' = 10
  | x == 'J' = 11
  | x == 'Q' = 12
  | x == 'K' = 13
  | x == 'A' = 14
  | otherwise = error ("digitToCard: Malformed input: " ++ show x)
