             [clojure.data.csv :as csv]
             [clojure.java.io :as io]
             [clojure.java.jdbc :as jdbc]
-            [clojure.string :as s]
-            [hugsql.core :as hugsql])
+            [clojure.string :as s])
   (:import com.ibm.icu.text.CharsetDetector
            java.util.UUID
            org.postgresql.PGConnection
            org.postgresql.copy.CopyManager))
 
+
 (defn- get-cols
-  ([num-cols]
-   (get-cols num-cols nil))
-  ([num-cols c-type]
-   (s/join ", "
-           (for [i (range 1 (inc num-cols))]
-             (str "c" i
-                  (if-not (nil? c-type)
-                    (str " " c-type)
-                    ""))))))
+  "Returns a vector of column names and PostgreSQL data types"
+  [num-cols & [col-type]]
+  (let [col-type-str (if col-type (str " " col-type) "")]
+    (vec (map #(str "c" % col-type-str)
+              (range 1 (inc num-cols))))))
 
-
-(defn get-create-table-sql
-  "Returns a `CREATE TABLE` statement for
-  the given number table name and number of columns"
-  [t-name num-cols]
-  (format "CREATE TABLE %s (%s, %s)"
-          t-name
-          "rnum serial primary key"
-          (get-cols num-cols "text")))
-
-(defn get-copy-sql
-  "Returns a `COPY` statement for the given
-  table and number of columns"
-  [t-name num-cols headers? encoding]
-  (format "COPY %s (%s) FROM STDIN WITH (FORMAT CSV, ENCODING '%s'%s)"
-          t-name
-          (get-cols num-cols)
-          encoding
-          (if headers? ", HEADER true" "")))
+(defn- create-table! ;; TODO handle column types other than "text"
+  "Creates a table of the given name & number of columns"
+  [tenant-conn table-name num-cols]
+  (let [sql (format "CREATE TABLE %s (rnum serial primary key, %s)"
+                    table-name
+                    (s/join ", " (get-cols num-cols "text")))]
+    (jdbc/execute! tenant-conn [sql])))
 
 (defn get-headers
-  "Returns the first line CSV a file"
+  "Returns the first line of the given CSV file"
   [path separator encoding]
-  (with-open [r (io/reader path :encoding encoding)]
-    (first (csv/read-csv r :separator separator))))
+  (with-open [reader (io/reader path :encoding encoding)]
+    (first (csv/read-csv reader :separator separator))))
 
 (defn get-num-cols
   "Returns the number of columns based on the


(defn get-encoding
  "Returns the character encoding reading some
  bytes from the file. It uses ICU's CharsetDetector"
  [path]
  (let [detector (CharsetDetector.)
        ;; 100kb
        ba (byte-array 100000)]
    (with-open [is (io/input-stream path)]
      (.read is ba))
    (-> (.setText detector ba)
        (.detect)
        (.getName))))

(defn get-column-tuples
  [col-titles]
  (vec
   (map-indexed (fn [idx title]
                  {:title title
                   :column-name (str "c" (inc idx))
                   :type "text"})
                col-titles)))

(defmethod import/valid? "CSV"
  [{:strs [url fileName hasColumnHeaders]}]

(defmethod import/make-dataset-data-table "CSV"
  [tenant-conn {:keys [file-upload-path]} table-name spec]
  (try
    (let [path (get-path spec file-upload-path)
          separator \,
          headers? (boolean (get spec "hasColumnHeaders"))
          encoding (get-encoding path)
          num-cols (get-num-cols path separator encoding)]
      (create-table! tenant-conn table-name num-cols)
      (insert-from-csv! tenant-conn table-name num-cols headers? path separator encoding)
      (let [col-titles (if headers?
                         (get-headers path separator encoding)
                         (vec (map #(str "Column " %)
                                   (range 1 (inc num-cols)))))]
        {:success? true
         :columns (get-column-tuples col-titles)}))
    (catch Exception e
      {:success? false
       :reason (str "Unexpected error: " (.getMessage e))})))
