from pprint import pprint as pp
import shared
import matrix


def part1(mx):
    SIZE = len(mx)
    MAX_IDX = SIZE - 1
    data = matrix.matrix_of_size(SIZE, SIZE)
    data = matrix.set_matrix_dict(data)

    for row in range(SIZE):
        for col in range(SIZE):
            data[row][col] = {"l": True, "r": True, "u": True, "d": True}

    for row, _row in enumerate(mx):
        # Skip outer edges
        if row == 0 or row == MAX_IDX:
            continue
        for col, _val in enumerate(mx[row]):
            # Skip outer edges
            if col == 0 or col == MAX_IDX:
                continue

            # TODO: slice
            # Get a list of indexes in the current direction to check
            trees_u_indexes = list(range(0, row))
            trees_l_indexes = list(range(0, col))
            trees_d_indexes = list(range(MAX_IDX, row, -1))
            trees_r_indexes = list(range(col + 1, SIZE))

            # Get the trees in the line
            trees_u = [mx[y][col] for y in trees_u_indexes]
            trees_l = [mx[row][x] for x in trees_l_indexes]
            trees_d = [mx[y][col] for y in trees_d_indexes]
            trees_r = [mx[row][x] for x in trees_r_indexes]

            # find tallest tree in line
            highest_u = max(trees_u)
            highest_l = max(trees_l)
            highest_d = max(trees_d)
            highest_r = max(trees_r)

            # if there's anything as tall, or taller than this tree in that line
            # then it's not visible
            if highest_u >= _val:
                data[row][col]["u"] = False

            if highest_l >= _val:
                data[row][col]["l"] = False

            if highest_d >= _val:
                data[row][col]["d"] = False

            if highest_r >= _val:
                data[row][col]["r"] = False

    # count visible
    count = 0
    for row in range(SIZE):
        for col in range(SIZE):
            u = data[row][col]["u"]
            l = data[row][col]["l"]
            d = data[row][col]["d"]
            r = data[row][col]["r"]
            if any((r, l, u, d)):
                count += 1
    print(count)


def part2(mx):
    SIZE = len(mx)
    MAX_IDX = SIZE - 1
    data = matrix.matrix_of_size(SIZE, SIZE)
    data = matrix.set_matrix_dict(data)

    high_score = 0

    for row in range(SIZE):
        for col in range(SIZE):
            data[row][col] = {"value": mx[row][col]}

    for row, _row in enumerate(mx):
        for col, _val in enumerate(mx[row]):
            # Get a list of indexes in the current direction to check
            # TODO: slice
            trees_u_indexes = list(range(0, row))
            trees_l_indexes = list(range(0, col))
            trees_d_indexes = list(range(MAX_IDX, row, -1))
            trees_r_indexes = list(range(col + 1, SIZE))

            # Grab the trees potentially in sight
            trees_u = [mx[y][col] for y in trees_u_indexes]
            trees_l = [mx[row][x] for x in trees_l_indexes]
            trees_d = [mx[y][col] for y in trees_d_indexes]
            trees_r = [mx[row][x] for x in trees_r_indexes]

            # Reverse everything but r, as everything is "away" from the tree
            data[row][col]["u"] = list(reversed(trees_u))
            data[row][col]["l"] = list(reversed(trees_l))
            data[row][col]["d"] = list(reversed(trees_d))
            data[row][col]["r"] = trees_r

            # Calculate score
            score = 1  # identity yoooo
            cell = data[row][col]
            val = cell["value"]
            # Get the score of visible trees in each direction
            for direction in ("u", "l", "d", "r"):
                in_line = cell[direction]
                if not in_line:
                    # we're on an edge
                    score = 0
                    break

                line_score = 0
                for idx, tree in enumerate(in_line):
                    # for every tree, check if its as tall or taller,
                    # stop countig after that
                    line_score += 1
                    if tree >= val:
                        break
                score = score * line_score
            if score > high_score:
                high_score = score
    print(high_score)


def part2_with_fixes(mx):
    SIZE = len(mx)
    MAX_IDX = SIZE - 1
    data = matrix.matrix_of_size(SIZE, SIZE)
    data = matrix.set_matrix_dict(data)

    high_score = 0

    for row in range(SIZE):
        for col in range(SIZE):
            data[row][col] = {"value": mx[row][col]}

    for row, _row in enumerate(mx):
        for col, _val in enumerate(mx[row]):
            lineofsight = matrix.line_of_sight(mx, row, col)

            data[row][col]["u"] = lineofsight["U"]
            data[row][col]["l"] = lineofsight["L"]
            data[row][col]["d"] = lineofsight["D"]
            data[row][col]["r"] = lineofsight["R"]

            # Calculate score
            score = 1  # identity yoooo
            val = data[row][col]["value"]
            # Get the score of visible trees in each direction
            for direction in ("u", "l", "d", "r"):
                in_line = data[row][col][direction]
                if not in_line:
                    # we're on an edge
                    score = 0
                    break

                line_score = 0
                for idx, tree in enumerate(in_line):
                    # for every tree, check if its as tall or taller,
                    # stop countig after that
                    line_score += 1
                    if tree >= val:
                        break
                score = score * line_score
            if score > high_score:
                high_score = score
    print(high_score)


def main():
    mx = matrix.load_matrix_file(shared.get_fname(8))
    with shared.elapsed_timer() as elapsed:
        part1(mx)
        print(elapsed())
    with shared.elapsed_timer() as elapsed:
        part2(mx)
        print(elapsed())
    with shared.elapsed_timer() as elapsed:
        part2_with_fixes(mx)
        print(elapsed())


if __name__ == "__main__":
    main()
