;; Search and actor card components

;; Aliases — delegate to shared ~avatar
(defcomp ~federation-actor-avatar-img (&key src cls)
  (~avatar :src src :cls cls))

(defcomp ~federation-actor-avatar-placeholder (&key cls initial)
  (~avatar :cls cls :initial initial))

(defcomp ~federation-actor-name-link (&key href name)
  (a :href href :class "font-semibold text-stone-900 hover:underline" name))

(defcomp ~federation-actor-name-link-external (&key href name)
  (a :href href :target "_blank" :rel "noopener"
    :class "font-semibold text-stone-900 hover:underline" name))

(defcomp ~federation-actor-summary (&key summary)
  (div :class "text-sm text-stone-600 mt-1 truncate" (~rich-text :html summary)))

(defcomp ~federation-unfollow-button (&key action csrf actor-url)
  (div :class "flex-shrink-0"
    (form :method "post" :action action :sx-post action :sx-target "closest article" :sx-swap "outerHTML"
      (input :type "hidden" :name "csrf_token" :value csrf)
      (input :type "hidden" :name "actor_url" :value actor-url)
      (button :type "submit" :class "text-sm border border-stone-300 rounded px-3 py-1 hover:bg-stone-100" "Unfollow"))))

(defcomp ~federation-follow-button (&key action csrf actor-url label)
  (div :class "flex-shrink-0"
    (form :method "post" :action action :sx-post action :sx-target "closest article" :sx-swap "outerHTML"
      (input :type "hidden" :name "csrf_token" :value csrf)
      (input :type "hidden" :name "actor_url" :value actor-url)
      (button :type "submit" :class "text-sm bg-stone-800 text-white rounded px-3 py-1 hover:bg-stone-700" label))))

(defcomp ~federation-actor-card (&key cls id avatar name username domain summary button)
  (article :class cls :id id
    avatar
    (div :class "flex-1 min-w-0"
      name
      (div :class "text-sm text-stone-500" "@" username "@" domain)
      summary)
    button))

(defcomp ~federation-search-info (&key cls text)
  (p :class cls text))

(defcomp ~federation-search-page (&key search-url search-page-url query info results)
  (h1 :class "text-2xl font-bold mb-6" "Search")
  (form :method "get" :action search-url :class "mb-6"
    :sx-get search-page-url :sx-target "#search-results" :sx-push-url search-url
    (div :class "flex gap-2"
      (input :type "text" :name "q" :value query
        :class "flex-1 border border-stone-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-stone-500"
        :placeholder "Search users or @user@instance.tld")
      (button :type "submit" :class "bg-stone-800 text-white px-6 py-2 rounded hover:bg-stone-700" "Search")))
  info
  (div :id "search-results" results))

;; Following / Followers list page
(defcomp ~federation-actor-list-page (&key title count-str items)
  (h1 :class "text-2xl font-bold mb-6" title " "
    (span :class "text-stone-400 font-normal" count-str))
  (div :id "actor-list" items))

;; ---------------------------------------------------------------------------
;; Assembled actor card — replaces Python _actor_card_sx
;; ---------------------------------------------------------------------------

(defcomp ~federation-actor-card-from-data (&key a actor followed-urls list-type)
  (let* ((display-name (or (get a "display_name") (get a "preferred_username") ""))
         (username (or (get a "preferred_username") ""))
         (domain (or (get a "domain") ""))
         (icon-url (get a "icon_url"))
         (actor-url (or (get a "actor_url") ""))
         (summary (get a "summary"))
         (aid (get a "id"))
         (safe-id (replace (replace actor-url "/" "_") ":" "_"))
         (initial (if (and (not icon-url) (or display-name username))
                    (upper (slice (or display-name username) 0 1)) "?"))
         (csrf (csrf-token))
         (is-followed (contains? (or followed-urls (list)) actor-url)))
    (~federation-actor-card
      :cls "bg-white rounded-lg shadow-sm border border-stone-200 p-4 mb-3 flex items-center gap-4"
      :id (str "actor-" safe-id)
      :avatar (~avatar
        :src icon-url
        :cls (if icon-url "w-12 h-12 rounded-full"
               "w-12 h-12 rounded-full bg-stone-300 flex items-center justify-center text-stone-600 font-bold")
        :initial (when (not icon-url) initial))
      :name (if (and (or (= list-type "following") (= list-type "search")) aid)
              (~federation-actor-name-link
                :href (url-for "social.defpage_actor_timeline" :id aid)
                :name (escape display-name))
              (~federation-actor-name-link-external
                :href (str "https://" domain "/@" username)
                :name (escape display-name)))
      :username (escape username)
      :domain (escape domain)
      :summary (when summary (~federation-actor-summary :summary summary))
      :button (when actor
        (if (or (= list-type "following") is-followed)
          (~federation-unfollow-button
            :action (url-for "social.unfollow") :csrf csrf :actor-url actor-url)
          (~federation-follow-button
            :action (url-for "social.follow") :csrf csrf :actor-url actor-url
            :label (if (= list-type "followers") "Follow Back" "Follow")))))))

;; Assembled search content — replaces Python _search_content_sx
(defcomp ~federation-search-content (&key query actors total followed-urls actor)
  (~federation-search-page
    :search-url (url-for "social.defpage_search")
    :search-page-url (url-for "social.search_page")
    :query (escape (or query ""))
    :info (cond
      ((and query (> total 0))
        (~federation-search-info
          :cls "text-sm text-stone-500 mb-4"
          :text (str total " result" (pluralize total) " for " (escape query))))
      (query
        (~federation-search-info
          :cls "text-stone-500 mb-4"
          :text (str "No results found for " (escape query))))
      (true nil))
    :results (when (not (empty? actors))
      (<>
        (map (lambda (a)
          (~federation-actor-card-from-data
            :a a :actor actor :followed-urls followed-urls :list-type "search"))
          actors)
        (when (>= (len actors) 20)
          (~federation-scroll-sentinel
            :url (url-for "social.search_page" :q query :page 2)))))))

;; Assembled following/followers content — replaces Python _following_content_sx etc.
(defcomp ~federation-following-content (&key actors total actor)
  (~federation-actor-list-page
    :title "Following" :count-str (str "(" total ")")
    :items (when (not (empty? actors))
      (<>
        (map (lambda (a)
          (~federation-actor-card-from-data
            :a a :actor actor :followed-urls (list) :list-type "following"))
          actors)
        (when (>= (len actors) 20)
          (~federation-scroll-sentinel
            :url (url-for "social.following_list_page" :page 2)))))))

(defcomp ~federation-followers-content (&key actors total followed-urls actor)
  (~federation-actor-list-page
    :title "Followers" :count-str (str "(" total ")")
    :items (when (not (empty? actors))
      (<>
        (map (lambda (a)
          (~federation-actor-card-from-data
            :a a :actor actor :followed-urls followed-urls :list-type "followers"))
          actors)
        (when (>= (len actors) 20)
          (~federation-scroll-sentinel
            :url (url-for "social.followers_list_page" :page 2)))))))
