 
     :status     String
     :id         Number
+    :pos        Number
     :title      String
     :acceptance String
     :difficulty Number {1,2,3}

render problem description."
  (interactive)
  (let* ((entry (tabulated-list-get-entry))
         (id (aref entry 1))
         (title (aref entry 2))
         (difficulty (aref entry 4))
         (problem (leetcode--parse-problem title))

(defun leetcode ()
  "Show leetcode problems buffer."
  (interactive)
  (unless (get-buffer leetcode--buffer-name)
    (leetcode--login leetcode--login-account leetcode--login-password)
    (with-current-buffer (get-buffer-create leetcode--buffer-name)
      (leetcode-problems-mode)
      (leetcode-problems-refresh)))
  (switch-to-buffer (get-buffer leetcode--buffer-name))
  (tabulated-list-print t))

;; TODO
;; (defun leetcode-test ()
;;   "Test the code using customized testcase."
;;   )

(defun leetcode-submit ()
  "Submit the code. "
  (interactive)
  (let* ((code (buffer-substring-no-properties (point-min) (point-max)))
         (title-slug (with-current-buffer (current-buffer)
                       (file-name-base (buffer-name))))
         (id (catch 'break
               (dolist (p (plist-get leetcode--problems :problems))
                 (when (string-equal title-slug (leetcode--title-slug (plist-get p :title)))
                   (throw 'break (plist-get p :id)))))))
    (let* ((csrftoken (leetcode--csrf-token))
           (url-request-method "POST")
           (url-request-extra-headers (list leetcode--User-Agent
                                            (leetcode--referer (format leetcode--problems-submission title-slug))
                                            (cons "Content-Type" "application/json")
                                            (cons leetcode--X-CSRFToken csrftoken)))
           (url-request-data (json-encode `((lang . ,leetcode-prefer-language)
                                            (question_id . ,id)
                                            (typed_code . ,code)))))
      (with-current-buffer (url-retrieve-synchronously (format leetcode--api-submit title-slug))
        (let ((submission-id (alist-get 'submission_id (json-read)))
              (url-request-method "POST")
              (url-request-extra-headers (list leetcode--User-Agent
                                               (leetcode--referer (format leetcode--problems-submission title-slug))
                                               (cons leetcode--X-CSRFToken csrftoken))))
          (let ((res (with-current-buffer (url-retrieve-synchronously (format leetcode--submission submission-id))
                       (json-read))))
            ;; poll until the state is SUCCESS
            (while (not (string-equal (alist-get 'state res) "SUCCESS"))
              (sleep-for 0.5)
              (setq res (with-current-buffer (url-retrieve-synchronously (format leetcode--submission submission-id))
                          (json-read))))
            (let ((runtime (alist-get 'status_runtime res))
                  (memory (alist-get 'status_memory res))
                  (runtime-perc (alist-get 'runtime_percentile res))
                  (memory-perc (alist-get 'memory_percentile res))
                  (total-correct (alist-get 'total_correct res))
                  (total-testcases (alist-get 'total_testcase res))
                  (status-msg (alist-get 'status_msg res))
                  (lang (alist-get 'pretty_lang res))
                  (display-buffer-alist (cons `(,leetcode--submit-buffer-name
                                                (display-buffer-reuse-window
                                                 display-buffer-in-side-window)
                                                (reusable-frames . visible)
                                                (side . bottom)
                                                (window-height . 0.3))
                                              display-buffer-alist)))
              (with-current-buffer (get-buffer-create leetcode--submit-buffer-name)
                (erase-buffer)
                (insert (format "Status: %s\n\n" status-msg))
                (when (string-equal status-msg "Accepted")
                  (insert (format "Runtime: %s, faster than %.2f%% of %s submissions.\n\n" runtime runtime-perc lang))
                  (insert (format "Memory Usage: %s, less than %.2f%% of %s submissions." memory memory-perc lang)))
                (display-buffer (current-buffer))))))))))

(defvar leetcode-problems-mode-map
  (let ((map (make-sparse-keymap)))
