module Day2

import Prelude
import Node

Draw : U
Draw = Int × Int × Int

data Game : U where
  MkGame : Int -> List Draw -> Game

-- Original had class and instance...
-- Add, Sub, Mul, Neg

max : Int -> Int -> Int
max x y = case x < y of
  True => y
  False => x

pfunc repr : {a : U} -> a -> String := `(a,o) => ''+o`
pfunc jrepr : {a : U} -> a -> String := `(a,o) => JSON.stringify(o, null, '  ')`
pfunc toInt : String -> Int := `s => Number(s)`

maxd : Draw -> Draw -> Draw
maxd (a,b,c) (d,e,f) = (max a d, max b e, max c f)

lte : Draw -> Draw -> Bool
lte (a,b,c) (d,e,f) = a <= d && b <= e && c <= f

parseColor : String -> Either String Draw
parseColor line = case split line " " of
  (n :: "red" :: Nil) => Right (toInt n,0,0)
  (n :: "green" :: Nil) => Right (0,toInt n,0)
  (n :: "blue" :: Nil) => Right (0,0,toInt n)
  x => Left $ "Bad draw" ++ repr x

-- FIXME implicit isn't being solved in time here.
parseDraw : String -> Either String Draw
parseDraw line =
  case mapM {Either String} parseColor $ split line ", " of
    Right parts => Right $ foldl maxd (0,0,0) parts
    Left err => Left err

parseGame : String -> Either String Game
parseGame line =
  let (a :: b :: Nil) = split line ": "
    | _ => Left $ "No colon in " ++ line in
  let ("Game" :: ns :: Nil) = split a " "
    | _ => Left $ "No Game" in
  let (Right parts) = mapM {Either String} parseDraw $ split b "; "
    | Left err => Left err in
  Right $ MkGame (toInt ns) parts

part1 : List Game -> Int
part1 Nil = 0
part1 (MkGame n parts :: rest) =
  let total = foldl maxd (0,0,0) parts in
  if lte total (12,13,14)
    then n + part1 rest
    else part1 rest

part2 : List Game -> Int
part2 Nil = 0
part2 (MkGame n parts :: rest) =
  let (a,b,c) = foldl maxd (0,0,0) parts
   in a * b * c + part2 rest

run : String -> IO Unit
run fn = do
  putStrLn fn
  text <- readFile fn
  let (Right games) = mapM {Either String} parseGame (split (trim text) "\n")
    | Left err => putStrLn $ "fail " ++ err
  putStrLn "part1"
  printLn (part1 games)
  putStrLn "part2"
  printLn (part2 games)

main : IO Unit
main = do
  run "aoc2023/day2/eg.txt"
  run "aoc2023/day2/input.txt"
