module AoC2021

using BenchmarkTools
using Markdown
using Printf
using Reexport
using Statistics

export benchmark_all, run_all

DAYS_DONE = [1,2,3,4,5,6,7,8,9,10,11,12,13,14]

name(day) = @sprintf("day%02d", day)

for day in DAYS_DONE
    dname = name(day)
    include("$dname.jl")
    @eval using .$(Symbol(uppercasefirst(dname)))
    @eval export $(Symbol(uppercasefirst(dname))), $(Symbol(dname))
end

function benchmark_all(days = DAYS_DONE; showall=false)
    totaltime = 0.0
    for day in days
        println("Benchmarking $day")
        b = @eval @benchmark $(Symbol(name(day)))()
        showall && display(b)
        totaltime += median(b.times)
    end
    println("Total time: ", round(totaltime*1e-6; sigdigits=4), "ms")
    return totaltime*1e-6
end

function run_all(days = DAYS_DONE)
    table = Markdown.Table([["Day", "Time", "Part 1", "Part 2"]], [:c, :c, :c, :c])
    for day in days
        res = @timed @eval $(Symbol(name(day)))()
        row = [ @sprintf("Day %02d", day),
                _format_time(res.time),
                string(res.value[1]),
                string(res.value[2])]
        push!(table.rows, row)
    end
    return Markdown.MD(table)
end

function _format_time(time; sigdigits=4)
    magnitudes = [1e-6, 1e-3, 1.0, 60]
    prefixes = ["ns", "µs", "ms", "s"]
    for (mag, pref) in zip(magnitudes, prefixes)
        if time < mag
            return "$(round(time/mag/1e-3; sigdigits))$pref"
        end
    end
    return "$(div(time,60))min $(round(mod(time, 60); digits=1))s"
end

end # module
