(ns edition2022.day8
  (:require [clojure.string :as str]
            [clojure.math.combinatorics :as comb]))

(def example-in "30373\n25512\n65332\n33549\n35390")
(def example-lines (str/split-lines example-in))

(defn read-in-lines []
  (str/split-lines (slurp "resources/day8.in")))

(defn int-row [row]
  (map #(- (int %) 48) (seq row)))

(defn append-columns [row columns]
  (->> (map vector row)
       (interleave columns)
       (partition 2)
       (map #(apply concat %)))
  )

(defn columns-from-rows [lines]
  (loop [rows (map seq lines)
         columns (take (count (first rows)) (iterate identity []))]
    (if (empty? rows)
      columns
      (recur (rest rows) (append-columns (first rows) columns)))))


(defn all-tree-positions [size]
  (comb/cartesian-product (range size) (range size)))

(defn tree-with-neighbours [pos rows cols]
  {:pos pos,
   :row (nth rows (first pos)),
   :col (nth cols (second pos))})

(defn trees-with-neighbours [lines]
  (let [rows (map int-row lines)
        cols (columns-from-rows rows)
        positions (all-tree-positions (count rows))]
    (map #(tree-with-neighbours % rows cols) positions)))

(defn highest-tree? [tree neighbours]
  (empty? (drop-while #(> tree %) neighbours)))

(defn visible-tree-from-one-direction? [idx row]
  (let [tree (nth row idx)
        left-side (take idx row)
        right-side (drop (+ idx 1) row)
        ]
    (or
      (= 0 idx)
      (= (- (count row) 1) idx)
      (highest-tree? tree left-side)
      (highest-tree? tree right-side))))

(defn visible-tree? [tree-with-neighbours]
  (let [pos (:pos tree-with-neighbours)
        x (second pos)
        y (first pos)
        row (:row tree-with-neighbours)
        col (:col tree-with-neighbours)
        ]
    (or
      (visible-tree-from-one-direction? x row)
      (visible-tree-from-one-direction? y col))))

(defn count-visible-trees [trees-with-neighbours]
  ;(map #(vector (visible-tree? %) %) trees-with-neighbours)
  (count (filter visible-tree? trees-with-neighbours))
  )

(defn solution-part-1 []
  (->> (read-in-lines)
       (trees-with-neighbours)
       (count-visible-trees)))

(defn view-distance [tree neighbours]
  (let [smaller-trees-count (count (take-while #(> tree %) neighbours))
        neighbours-count (count neighbours)
        blocking-tree (nth neighbours smaller-trees-count nil)]
    (cond
      (not (nil? blocking-tree)) (+ smaller-trees-count 1)
      :else smaller-trees-count)))

(defn scenic-score-from-one-direction [idx row]
  (let [tree (nth row idx)
        left-side (reverse (take idx row))
        right-side (drop (+ idx 1) row)]
    (cond
      (= 0 idx) 0
      (= (- (count row) 1) idx) 0
      :else
      (*
        (view-distance tree left-side)
        (view-distance tree right-side)))))

(defn scenic-score [tree-with-neighbours]
  (let [pos (:pos tree-with-neighbours)
        x (second pos)
        y (first pos)
        row (:row tree-with-neighbours)
        col (:col tree-with-neighbours)
        ]
    (*
      (scenic-score-from-one-direction x row)
      (scenic-score-from-one-direction y col))))

(defn max-scenic-score [trees-with-neighbours]
  (->> trees-with-neighbours
       (map scenic-score)
       (reduce max)
       )
  )

(defn solution-part-2 []
  (->> (read-in-lines)
       (trees-with-neighbours)
       (max-scenic-score)))

(comment
  (append-columns [1 2 3 4] [[0] [0] [0] [0]])
  example-lines
  (columns-from-rows example-lines)
  (all-tree-positions 4)
  (count (all-tree-positions 3))
  (count (all-tree-positions 5))
  (trees-with-neighbours example-lines)
  (visible-tree-from-one-direction? 4 '(3 0 3 7 3))
  (visible-tree? {:pos '(1 1), :row '(2 5 5 1 2), :col '(0 5 5 3 5)})
  (scenic-score {:pos '(1 1), :row '(2 5 5 1 2), :col '(0 5 5 3 5)})
  (scenic-score {:pos '(3 2), :row '(3 3 5 4 9), :col '(3 5 3 5 3)})
  (scenic-score-from-one-direction 2 '(3 3 5 4 9))
  (view-distance 5 [3 3])
  (view-distance 5 [4 9])
  (scenic-score-from-one-direction 3 '(3 5 3 5 3))
  (count-visible-trees (trees-with-neighbours example-lines))
  (max-scenic-score (trees-with-neighbours example-lines))
  (solution-part-1)
  (solution-part-2)
  )