import std/strutils
import std/sequtils
import std/algorithm
import std/re

type
  DirEntry = ref object
    parent: DirEntry
    name: string
    dirs: seq[DirEntry]
    files: seq[FileEntry]
  FileEntry = ref object
    name: string
    size: int


proc mkcd(a: DirEntry, name: string): DirEntry =
  for i in 0.. (a.dirs.len() - 1):
    if a.dirs[i].name == name:
        return a.dirs[i]
  a.dirs.add(DirEntry(parent: a, name: name, dirs: @[], files: @[]))
  return a.dirs[len(a.dirs)-1]

proc recursive_size(a: DirEntry): int =
    var sz = 0
    for d in a.dirs:
        sz += d.recursive_size()
    for f in a.files:
        sz += f.size
    return sz

proc sum_size_sub(a: DirEntry, max: int): int =
    let sz = a.recursive_size()
    var res = 0
    if sz < max:
        res += sz
    for d in a.dirs:
        res += d.sum_size_sub(max)
    return res

proc print(a: DirEntry, indent: int) =
    echo ' '.repeat(indent*2), a.name, " (sz = ", a.recursive_size(), " )"
    echo ' '.repeat(indent*2), "{"
    for f in a.files:
        echo ' '.repeat(indent*2+2), "[F] ", f.name, " (sz = ", f.size, " )"
    for d in a.dirs:
        d.print(indent+1)
    echo ' '.repeat(indent*2), "}"

proc collect_dirs(a: DirEntry, coll: var seq[DirEntry]) =
    coll.add(a)
    for d in a.dirs:
        coll.add(d)
        d.collect_dirs(coll)


proc run07_2(): string =
    const input = staticRead"../input/day07.txt"

    let lines = splitLines(input).filter(proc(p: string): bool = p != "")

    var root = DirEntry(parent: nil, name: "/", dirs: @[], files: @[])

    var curr = root

    for line in lines:
        if line == "$ cd ..":
            curr = curr.parent
        elif line.startsWith("$ cd "):
            curr = curr.mkcd(line.substr(5))
        elif line == "$ ls":
            continue
        elif line.startsWith("dir "):
            discard curr.mkcd(line.substr(4))
        elif line.match(re"^[0-9].*"):
            let split = line.split(" ")
            curr.files.add(FileEntry(name: split[1], size: parseInt(split[0])))
        else:
            echo "UNKNOWN LINE: " & line


    # echo root.recursive_size()

    # root.print(0)

    var dirs: seq[DirEntry] = @[]
    root.collect_dirs(dirs)

    proc scmp(a, b: DirEntry): int =
        if a.recursive_size() < b.recursive_size(): -1
        else: 1

    dirs.sort(scmp)

    let min_size = -(70000000 - 30000000 - root.recursive_size())

    # echo min_size

    for d in dirs:
        if d.recursive_size() > min_size:
            return intToStr(d.recursive_size())

    return "ERR"


when not defined(js):
    echo run07_2()
else:
    proc js_run07_2(): cstring {.exportc.} =
        return cstring(run07_2())