(defun treesit-docgen--get-function-node (node)
  "Get the function node the given NODE belongs to. Or nil"
  (treesit-parent-until node
                        (lambda (n)
                          (or (equal (treesit-node-type n) "function_definition")
                              (and (equal (treesit-node-type n) "declaration"))
                              (equal (treesit-node-type (treesit-node-child-by-field-name n "declarator"))
                                     "function_declarator")))
                        t)
  )

(defun treesit-docgen--fn-template-node (fn-node)
  "Get the template node of a function or nil"
  (let* ((par (treesit-node-parent fn-node))
         (par-t (treesit-node-type par)))
    (when (string= par-t "template_declaration") par)
    ))

(defun treesit-docgen--fn-tpars (fn-node)
  "Get the template parameters of the function node or nil"
  (let* ((template (treesit-docgen--fn-template-node fn-node))
         (tpars (treesit-node-child-by-field-name template "parameters")))
    (when tpars
      (delq nil
            (mapcar (lambda (tpar) (when (string= (treesit-node-type tpar) "type_parameter_declaration")
                                     (treesit-node-text tpar)))
                    (treesit-node-children tpars))))))

(defun treesit-docgen--fn-type (fn-node)
  "Get the return type of the function node"
  (let ((fn-type-node (treesit-node-child-by-field-name fn-node "type")))
    (treesit-node-text fn-type-node)))

(defun treesit-docgen--fn-pars (fn-node)
  "Get the parameter names of the function node"
  (let* ((fn-node-decl (treesit-node-child-by-field-name fn-node "declarator"))
         (fn-node-pars (treesit-node-child-by-field-name fn-node-decl "parameters"))
         )
    (when fn-node-pars
      (delq nil
            (mapcar (lambda (par) (when (string= (treesit-node-type par) "parameter_declaration")
                                    (treesit-node-text par)))
                    (treesit-node-children fn-node-pars))))))

(defun treesit-docgen-insert-doc ()
  "Insert a documentation template for the function at point"
  (interactive)
  (let* ((node (treesit-node-at (point)))
         (fn-node (treesit-docgen--get-function-node node)))
    (when fn-node
      (let* ((fn-type (treesit-docgen--fn-type fn-node))
             (fn-pars (treesit-docgen--fn-pars fn-node))
             (fn-tpars (treesit-docgen--fn-tpars fn-node)))
        (goto-char (treesit-node-start
                    (or (treesit-docgen--fn-template-node fn-node)
                        fn-node)))
        (insert "///\n")
        (insert "///@brief\n")
        (insert "///\n")
        (when fn-tpars
          (dolist (tpar fn-tpars)
            (insert "///@tparam " tpar "\n"))
          (insert "///\n"))
        (when fn-pars
          (dolist (par fn-pars)
            (insert "///@param " par "\n"))
          (insert "///\n"))
        (when fn-type
          (insert "///@return " fn-type "\n")
          (insert "///\n")
          )))))
