const reversedCopy = (array) => {
    array = Array.from(array);
    array.reverse();
    return array;
}

const multiply = (array) => array.reduce((prev, curr) => prev * curr);

const flatten = (arr) => {
    return arr.reduce(function (flat, toFlatten) {
      return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
    }, []);
  }

const countInArray = (array, idGenerator) => {
    const visibleTrees = [];
    let maxHeight = -1;
    for (let j=0; j < array.length; j++) {
        if (array[j] > maxHeight) {
            visibleTrees.push(idGenerator(j));
            maxHeight = array[j];
        }
    }
    return visibleTrees;
}

const getVisibleRow = (matrix, rowIndex, reverse) => {
    let row = matrix[rowIndex];
    if (reverse) {
        row = reversedCopy(row);
    }
    return countInArray(row, (idx) => {
        return [
            rowIndex, 
            reverse ? row.length -1 - idx : idx
        ]
    });
}

const getVisibleColumn = (matrix, columnIndex, reverse) => {
    let column = matrix.map(row => {
        return row[columnIndex];
    })

    if (reverse) {
        column = reversedCopy(column);
    }
    return countInArray(column, (idx) => {
        return [
            reverse ? column.length - 1 - idx : idx, 
            columnIndex
        ]
    });
}


const main = (inputString) => {
    const matrix = inputString
        .split('\n')
        .map(line => {
            return line.split('');
        })
    const rowCount = matrix.length;
    const colCount = matrix[0].length;

    let visibleTrees = [];
    for (let i=0; i < rowCount; i++) {
        visibleTrees = visibleTrees
                            .concat(getVisibleRow(matrix, i, false))
                            .concat(getVisibleRow(matrix, i, true));
    }
    for (let i=0; i < colCount; i++) {
        visibleTrees = visibleTrees
                            .concat(getVisibleColumn(matrix, i, false))
                            .concat(getVisibleColumn(matrix, i, true));
    }
    const set = new Set(visibleTrees.map(t => `${t[0]}-${t[1]}`));
    console.log('part 1', set.size);

    // brute force in all directions
    const directions = [
        [-1, 0],
        [1, 0],
        [0, 1],
        [0, -1]
    ];
    const scores = matrix.map((row, i) => {
        return row.map((height, j) => {
            const scores = directions.map(dir => {
                let x = i + dir[0];
                let y = j + dir[1];
                let viewDistance = 0;
                while (x >= 0 && x < matrix.length 
                    && y >= 0 && y < row.length) {
                        viewDistance++;
                        if (matrix[x][y] >= height) {
                            break;
                        }
                        x += dir[0];
                        y += dir[1];
                }
                return viewDistance;
            })
            return multiply(scores)
        })
    })
    console.log('part 2', Math.max.apply(Math, flatten(scores)));
}