(import-macros {: exec : map!} :hibiscus.vim)

(local M {})

(local files
  {:dictionary (.. (vim.fn.stdpath "config") "/spell/en.utf-8.add")
   :disabledRules (.. (vim.fn.stdpath "config") "/spell/disable.txt")
   :hiddenFalsePositives (.. (vim.fn.stdpath "config") "/spell/false.txt")})

(fn file_exists [file]
  (let [f (io.open file "rb")]
    (if f
          (do (f:close) true)
        false)))

(fn lines_from [file]
  (if (file_exists file)
        (icollect [line (io.lines file)] line)
      []))

(fn get_client_by_name [name]
  (let [buf_clients (vim.lsp.buf_get_clients)]
    (var found_client nil)
    (each [_ client (ipairs buf_clients) :until found_client]
      (match client.name name (set found_client client)))
    found_client))

(fn update_config [lang configtype]
  (let [client (get_client_by_name "ltex")] 
  (if (and client (. client.config.settings.ltex configtype))
        (do (tset client.config.settings.ltex configtype {lang (lines_from (. files configtype))})
            (client.notify "workspace/didChangeConfiguration" client.config.settings))
      (vim.notify "Error when reading dictionary config, check it"))))

(fn add_to_file [configtype lang file value]
  (let [dict (lines_from file)]
    (var found_existing false)
    (each [_ v (ipairs dict) :until found_existing]
      (if (= v value) (set found_existing true)))
    (if (not found_existing)
          (let [file (io.open file "a+")]
            (if file
                  (do (file:write (.. value "\n"))
                      (file:close)
                      (update_config lang configtype))
                (vim.notify (string.format "Failed insert %s" value)))))))

(fn do_command [arg configtype]
  (each [lang words (pairs arg)]
    (each [_ word (ipairs words)]
      (add_to_file configtype lang (. files configtype) word))))

(tset vim.lsp.commands "_ltex.addToDictionary"
      (fn [command _] (do_command (. command.arguments 1 :words) :dictionary)))
(tset vim.lsp.commands "_ltex.disableRules"
      (fn [command _] (do_command (. command.arguments 1 :ruleIds) :disabledRules)))
(tset vim.lsp.commands "_ltex.hideFalsePositives"
      (fn [command _] (do_command (. command.arguments 1 :falsePositives) :hiddenFalsePositives)))

(fn post_attach []
  (exec [[:setlocal "spell"] [:setlocal "nospell"]])
  (update_config "en-US" "dictionary")
  (update_config "en-US" "disabledRules")
  (update_config "en-US" "hiddenFalsePositives")
  (map! [n :buffer :verbose] :zug (fn [] (exec [[:normal! "zug"]])
                                         (update_config "en-US" "dictionary")
                                         nil)
        "Remove word from spellfile and update ltex")
  (map! [n :buffer :verbose] :zg (fn [] (exec [[:normal! "zg"]])
                                        (update_config "en-US" "dictionary")
                                        nil)
        "Add word to spellfile and update ltex")
  nil)

(fn M.setup [opts]
  ((. (require :lspconfig) :ltex :setup)
    {:on_attach (fn [client] (opts.on_attach client)
                             (post_attach)
                             nil)
     :capabilities opts.capabilities
     :flags opts.flags
     :settings {:ltex {:dictionary           []
                       :disabledRules        []
                       :hiddenFalsePositives []}
                       :additionalRules {:enablePickyRules true}}}))

M
