#!/usr/bin/env sh
:$(); -*- mode: clojure -*-
:$(); bb --init "$0" -- "$@" || exit=$?
:$(); exit $exit
(ns port-tools
  (:require [babashka.cli :as cli]
            [babashka.process :as p]))

(defn adorn-with-help-option [spec]
  (letfn [(fn-with-help [opts]
            ;; TODO: Implement
            ((:fn spec) opts))]
    (-> spec
        (assoc-in [:spec :help]
                  {:help {:coerce :bool}})
        (assoc :fn fn-with-help))))

(defn ip46tables [& args]
  (try
    (apply p/shell "iptables" args)
    (apply p/shell "ip6tables" args)
    (catch Exception e
      (println "ip6?tables failed!"))))

(defn open-port [{{:keys [ports]} :opts
                  :as opts}]
  (doseq [port ports]
    (ip46tables
     "-I" "nixos-fw" "1" "-p" "tcp" "--dport" port "-j" "nixos-fw-accept")
    (binding [*out* *err*]
      (printf "Opened port %d\n" port))))

(defn close-port [{:keys [ports] :as opts}]
  (doseq [port ports]
    (ip46tables
     "-D" "nixos-fw" "-p" "tcp" "--dport" port "-j" "nixos-fw-accept")
    (binding [*out* *err*]
      (printf "Closed port %d\n" port))))

(defn run-with-port [opts]
  (let [[ports [_ & cmd]] (split-with #(not= % "--") (:args opts))]
    (throw (ex-info "TODO: Implement me!" {}))))

(defn port? [x]
  (and (nat-int? x)
       (<= x 65535)))

(defn parse-port [x]
  (when-let [x* (parse-long x)]
    (and (<= 0 x* 65535) x*)))

(defn help [opts]
  (prn 'help))

(def port-option
  {:ports {:coerce [parse-port]
           :alias :p
           :ref "PORT"}})

(def cli-table
  (map adorn-with-help-option
       [{:cmds ["open"]
         :fn open-port
         :spec port-option
         :args->opts [:ports]}
        {:cmds ["close"]
         :spec port-option
         :fn close-port
         :args->opts [:ports]}
        {:cmds ["run-with-port"]
         :spec port-option
         :fn run-with-port}
        {:cmds []
         :fn help}]))

(defn -main [& args]
  (cli/dispatch cli-table args))

#_
(apply -main *command-line-args*)
