package main

import "core:bytes"
import "core:fmt"
import "core:math"
import "core:os"
import "core:strconv"
import "core:strings"

Race :: struct {
	time:     int,
	distance: int,
}

Input :: struct {
	races: [dynamic]Race,
}

Result1 :: distinct int
Result2 :: distinct int


// --- Input --- //
print_input :: proc(input: ^Input) {
	fmt.printf("%#v\n", input)
}

parse_input_file :: proc(filepath: string) -> Input {
	input: Input

	raw_data, ok := os.read_entire_file_from_filename(filepath)
	if !ok {
		panic("oh no, could not read file")
	}

	buf: bytes.Buffer
	bytes.buffer_init(&buf, raw_data)
	defer bytes.buffer_destroy(&buf)

	input.races = make([dynamic]Race, 0, 10)

	times, distances: []int
	{
		line, _ := bytes.buffer_read_string(&buf, '\n')
		line = line[:len(line) - 1]
		line_parts := strings.split(line, ":")
		defer delete(line_parts)
		numbers := strings.fields(line_parts[1])
		times = make([]int, len(numbers))
		for n, i in numbers {
			times[i] = strconv.atoi(n)
		}
	}
	defer delete(times)
	{
		line, _ := bytes.buffer_read_string(&buf, '\n')
		line = line[:len(line) - 1]
		line_parts := strings.split(line, ":")
		defer delete(line_parts)
		numbers := strings.fields(line_parts[1])
		distances = make([]int, len(numbers))
		for n, i in numbers {
			distances[i] = strconv.atoi(n)
		}
	}
	defer delete(distances)

	for i in 0 ..< len(times) {
		append(&input.races, Race{time = times[i], distance = distances[i]})
	}

	return input
}

free_input :: proc(input: ^Input) {
	delete(input.races)
}
// --- Input --- //


// --- Task 1 --- //
run_task1 :: proc(input: ^Input, debug: bool) -> Result1 {
	result: Result1 = 1

	if debug {
		print_input(input)
	}

	for race in input.races {
		min, max: f32

		s := math.sqrt(f32((race.time * race.time) - (4 * -1 * -race.distance)))
		min = (f32(-race.time) + s) / -2
		max = (f32(-race.time) - s) / -2
		min = math.ceil(min + 1) if math.ceil(min) == min else math.ceil(min)
		max = math.floor(max - 1) if math.floor(max) == max else math.floor(max)

		result *= Result1(max - min + 1)
	}

	return result
}

print_result1 :: proc(result: ^Result1) {
	fmt.printf("Task 1: %d\n", result^)
}
// --- Task 1 --- //


// --- Task 2 --- //
run_task2 :: proc(input: ^Input, debug: bool) -> Result2 {
	if debug {
		print_input(input)
	}

	time, distance: int
	for race in input.races {
		if race.time < 10 {
			time *= 10
		} else if race.time < 100 {
			time *= 100
		} else if race.time < 1000 {
			time *= 1000
		} else if race.time < 10000 {
			time *= 10000
		}
		time += race.time
		if race.distance < 10 {
			distance *= 10
		} else if race.distance < 100 {
			distance *= 100
		} else if race.distance < 1000 {
			distance *= 1000
		} else if race.distance < 10000 {
			distance *= 10000
		}
		distance += race.distance
	}
	fmt.printf("%d %d\n", time, distance)

	min, max: f64
	s := math.sqrt(f64((time * time) - (4 * -1 * -distance)))
	min = (f64(-time) + s) / -2
	max = (f64(-time) - s) / -2
	min = math.ceil(min + 1) if math.ceil(min) == min else math.ceil(min)
	max = math.floor(max - 1) if math.floor(max) == max else math.floor(max)

	return Result2(max - min + 1)
}

print_result2 :: proc(result: ^Result2) {
	fmt.printf("Task 2: %d\n", result^)
}
// --- Task 2 --- //