-(ns project-euler.problem_0127)
+(ns project-euler.problem_0127
+  (:require [clojure.math.combinatorics :as combo])
+  (:require [clojure.set :as set])
+  )
 
 ;; The radical of n, rad(n), is the product of distinct prime factors of n.
 ;; For example, 504 = 2^3 × 3^2 × 7, so rad(504) = 2 × 3 × 7 = 42.

          (== p q)        (recur (quot x p) p                       p r)
          :else           (recur (quot x p) p                       p (* r p))
        )))

(defn naive-solution-for [c-max]
  (->> (range 3 c-max)

       (reduce +)
       ;;(count)
       ))

;; (defn solution-for [c-max]
;;   (->> (range 3 c-max)
;;        (map (fn [c] [c (decompose c)]))
;;        (filter (fn [[c [r upfs mpfs]]] (seq mpfs)))
;;        ;;(filter (fn [[c [r upfs mpfs]]] (>= (/ c r) 6)))
;;        ;;(count)
;;        (mapcat (fn [[c [r upfs mpfs]]]
;;                  (->> (if (odd? c) (iterate inc 1) (iterate #(+ % 2) 1))
;;                       (map (fn [a] [a (- c a) c]))
;;                       (take-while (fn [[a b c]] (< a b)))
;;                       (remove (fn [[a b c]]
;;                                 (some #(or (zero? (rem a %))
;;                                            (zero? (rem b %))) upfs)
;;                                 ))
;;                       )
;;                  ))
;;        (filter (fn [[a b c]] (< (rad (* a b c)) c)))
;;        (map (fn [[a b c]] c))
;;        (reduce +)
;;        ))

;; (defn solutions-for-a [rad-ab c-pfs]
;;   (let [ab-pfs (->> primes
;;                     (take-while #(< % rad-ab))
;;                     (filter #(== -1 (.indexOf c-pfs %)))
;;                     )]
;;     (products-under rad-ab ab-pfs)))

(defn products-under [p-max xs]
  (let [[x & xs'] xs]
    (if x
      (->> (iterate (fn [[p p-max']] [(* p x) (/ p-max' x)]) [1 p-max])
                (take-while (fn [[p p-max']] (< p p-max)))
                (mapcat (fn [[p p-max']]
                          (map #(* p %) (products-under p-max' xs'))))
                )
      [1]
      )))

(defn solutions-for-ab [c r c-pfs]
  (let [ab-pfs (->> primes
                    (take-while #(< % (/ c r)))
                    (filter #(== -1 (.indexOf c-pfs %)))
                    )]
    (println ab-pfs)
    (->> (products-under (/ c r) ab-pfs)
         (mapcat (fn [pb]
                   (->> ab-pfs
                        (filter #(and (not (zero? (rem pb %)))
                                      (< % (/ c r (rad pb)))
                                      ))
                        (products-under pb)
                        (map (fn [pa] [pa pb]))
                        (filter (fn [[a b]] (== c (+ a b))))
                        (map (fn [[a b]] [a b c]))
                        )
                   ))
         )))


;; (defn prime-factors-pairs [p-max xs]
;;   (->> (combo/subsets xs)
;;        (filter seq)
;;        (filter #(<= (apply * %) p-max))
;;        (mapcat (fn [a-ss]
;;                  (->> (set/difference (set xs) (set a-ss))
;;                       (vec)
;;                       (combo/subsets)
;;                       (filter seq)
;;                       (filter #(<= (apply * %) p-max))
;;                       (map (fn [b-ss] [a-ss b-ss]))
;;                       )))
;;        ))

;; (defn solutions-for-ab [p-max c-pfs]
;;   (let [ab-pfs (->> primes
;;                     (take-while #(< % p-max))
;;                     (filter #(== -1 (.indexOf c-pfs %)))
;;                     )]
;;     (->> (prime-factors-pairs p-max ab-pfs)
;;          (mapcat (fn [[a-ss b-ss]]
;;                    (->> (products-under p-max b-ss)
;;                         (mapcat (fn [pb]
;;                                   (->> (products-under pb a-ss)
;;                                        (map (fn [pa] [pa pb])))))
;;                         )))
;;          )))



(defn solution-for [c-max]
  (->> (range 3 c-max)
       (map (fn [c] [c (decompose c)]))
       (filter (fn [[c [r upfs mpfs]]] (seq mpfs)))
       (mapcat (fn [[c [r upfs mpfs]]]
                 (->> (solutions-for-ab c r upfs)
                      )))
       ;;(drop 20)
       (remove abc-hit?)
       (take 10)
       ;;(count)
       
       ;;(filter (fn [[a b c]] (< (rad (* a b c)) c)))
       ;;(map (fn [[a b c]] c))
       ;;(reduce +)
       ))


