package day_06

import "core:log"
import "core:os"
import "core:strconv"
import "core:strings"

Op :: enum (u8) {
	None,
	Add = '+',
	Mul = '*',
}

Column :: struct {
	op:        Op,
	starts_at: int,
	ends_at:   int,
	nums:      []string,
}

Input :: struct {
	columns: []Column,
}

Result1 :: int
Result2 :: int

// --- Input --- //
print_input :: proc(input: Input) {
	log.infof("%#v", 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")
	}
	defer delete(raw_data)

	lines, err := strings.split_lines(string(raw_data))
	if err != .None {
		panic("oh no, failed splitting into lines")
	}
	defer delete(lines)

	last := len(lines) - 2
	num_nums := last
	num_columns: int
	for _, i in lines[last] {
		line := lines[last]
		if line[i] == u8(Op.Add) || line[i] == u8(Op.Mul) {
			num_columns += 1
		}
	}

	input.columns = make([]Column, num_columns)
	for &c in input.columns {
		c.nums = make([]string, num_nums)
	}

	col: int
	for _, i in lines[last] {
		line := lines[last]
		if line[i] == u8(Op.Add) || line[i] == u8(Op.Mul) {
			input.columns[col].op = Op(line[i])
			input.columns[col].starts_at = i
			if col > 0 {
				input.columns[col - 1].ends_at = i - 1
			}
			col += 1
		}
		input.columns[col - 1].ends_at = len(line)
	}

	for c in input.columns {
		for line, i in lines[:last] {
			c.nums[i] = strings.clone(line[c.starts_at:c.ends_at])
		}
	}

	return input
}

free_input :: proc(input: ^Input) {
	for c in input.columns {
		for _, i in c.nums {
			delete(c.nums[i])
		}
		delete(c.nums)
	}
	delete(input.columns)
	input.columns = nil
}
// --- Input --- //


// --- Helpers --- //
// --- Helpers --- //


// --- Task 1 --- //
run_task1 :: proc(input: Input) -> Result1 {
	result: Result1

	for c in input.columns {
		val: int
		if c.op == .Add {
			for n in c.nums {
				val += strconv.parse_int(strings.trim_space(n)) or_else 0
			}
		} else if c.op == .Mul {
			val = 1
			for n in c.nums {
				val *= strconv.parse_int(strings.trim_space(n)) or_else 0
			}
		}
		log.debugf("%v => %d", c, val)
		result += val
	}

	return result
}

print_result1 :: proc(result: Result1) {
	log.infof("Task 1: %d", result)
}
// --- Task 1 --- //


// --- Task 2 --- //
run_task2 :: proc(input: Input) -> Result2 {
	result: Result2

	for c_i in 0 ..< len(input.columns) {
		c := input.columns[len(input.columns) - 1 - c_i]
		r := c.ends_at - c.starts_at
		total := 1 if c.op == .Mul else 0
		for i in 0 ..< r {
			val := 0
			for num in c.nums {
				digit := num[r - 1 - i]
				if digit != ' ' {
					val = (val * 10) + int(digit - '0')
				}
			}
			if c.op == .Add {
				total += val
			} else if c.op == .Mul {
				total *= val
			}
			log.debugf("-> %d", val)
		}
		log.debugf("== %d", total)
		result += total
	}

	return result
}

print_result2 :: proc(result: Result2) {
	log.infof("Task 2: %d", result)
}
// --- Task 2 --- //

run :: proc() {
	input := parse_input_file("input/day_06.txt")
	defer free_input(&input)

	result1 := run_task1(input)
	print_result1(result1)

	result2 := run_task2(input)
	print_result2(result2)
}