text: import PostCooked from "discourse/widgets/post-cooked";
  import DecoratorHelper from "discourse/widgets/decorator-helper";
  import { createWidget, applyDecorators } from "discourse/widgets/widget";
  import { iconNode } from "discourse-common/lib/icon-library";
  import { transformBasicPost } from "discourse/lib/transform-post";
  import { h } from "virtual-dom";
  import DiscourseURL from "discourse/lib/url";
  import { dateNode } from "discourse/helpers/node";
  import {
    translateSize,
    avatarUrl,
    formatUsername
  } from "discourse/lib/utilities";
  import hbs from "discourse/widgets/hbs-compiler";
  
  export function avatarImg(wanted, attrs) {
    const size = translateSize(wanted);
    const url = avatarUrl(attrs.template, size);
  
    // We won't render an invalid url
    if (!url || url.length === 0) {
      return;
    }
    const title = attrs.name || formatUsername(attrs.username);
  
    let className =
      "avatar" + (attrs.extraClasses ? " " + attrs.extraClasses : "");
  
    const properties = {
      attributes: {
        alt: "",
        width: size,
        height: size,
        src: Discourse.getURLWithCDN(url),
        title
      },
      className
    };
  
    return h("img", properties);
  }
  
  export function avatarFor(wanted, attrs) {
    return h(
      "a",
      {
        className: `trigger-user-card ${attrs.className || ""}`,
        attributes: { href: attrs.url, "data-user-card": attrs.username }
      },
      avatarImg(wanted, attrs)
    );
  }
  
  createWidget("select-post", {
    tagName: "div.select-posts",
  
    html(attrs) {
      const buttons = [];
  
      if (!attrs.selected && attrs.post_number > 1) {
        if (attrs.replyCount > 0) {
          buttons.push(
            this.attach("button", {
              label: "topic.multi_select.select_replies.label",
              title: "topic.multi_select.select_replies.title",
              action: "selectReplies",
              className: "select-replies"
            })
          );
        }
        buttons.push(
          this.attach("button", {
            label: "topic.multi_select.select_below.label",
            title: "topic.multi_select.select_below.title",
            action: "selectBelow",
            className: "select-below"
          })
        );
      }
  
      const key = `topic.multi_select.${
        attrs.selected ? "selected" : "select"
      }_post`;
      buttons.push(
        this.attach("button", {
          label: key + ".label",
          title: key + ".title",
          action: "togglePostSelection",
          className: "select-post"
        })
      );
  
      return buttons;
    }
  });
  
  createWidget("reply-to-tab", {
    tagName: "a.reply-to-tab",
    buildKey: attrs => `reply-to-tab-${attrs.id}`,
  
    defaultState() {
      return { loading: false };
    },
  
    html(attrs, state) {
      if (state.loading) {
        return I18n.t("loading");
      }
  
      return [
        iconNode("mail-forward"),
        " ",
        avatarImg("small", {
          template: attrs.replyToAvatarTemplate,
          username: attrs.replyToUsername
        }),
        " ",
        h("span", formatUsername(attrs.replyToUsername))
      ];
    },
  
    click() {
      this.state.loading = true;
      this.sendWidgetAction("toggleReplyAbove").then(
        () => (this.state.loading = false)
      );
    }
  });
  
  createWidget("post-avatar-user-info", {
    tagName: "div.post-avatar-user-info",
  
    html(attrs) {
      return this.attach("poster-name", attrs);
    }
  });
  
  createWidget("post-avatar", {
    tagName: "div.topic-avatar",
  
    settings: {
      size: "large",
      displayPosterName: false
    },
  
    html(attrs) {
      let body;
      if (!attrs.user_id) {
        body = iconNode("trash-o", { class: "deleted-user-avatar" });
      } else {
        body = avatarFor.call(this, this.settings.size, {
          template: attrs.avatar_template,
          username: attrs.username,
          name: attrs.name,
          url: attrs.usernameUrl,
          className: "main-avatar"
        });
      }
  
      const result = [body];
  
      if (attrs.primary_group_flair_url || attrs.primary_group_flair_bg_color) {
        result.push(this.attach("avatar-flair", attrs));
      }
  
      result.push(h("div.poster-avatar-extra"));
  
      if (this.settings.displayPosterName) {
        result.push(this.attach("post-avatar-user-info", attrs));
      }
  
      return result;
    }
  });
  
  createWidget("post-locked-indicator", {
    tagName: "div.post-info.post-locked",
    template: hbs`{{d-icon "lock"}}`,
    title: () => I18n.t("post.locked")
  });
  
  createWidget("post-email-indicator", {
    tagName: "div.post-info.via-email",
  
    title(attrs) {
      return attrs.isAutoGenerated
        ? I18n.t("post.via_auto_generated_email")
        : I18n.t("post.via_email");
    },
  
    buildClasses(attrs) {
      return attrs.canViewRawEmail ? "raw-email" : null;
    },
  
    html(attrs) {
      return attrs.isAutoGenerated
        ? iconNode("envelope")
        : iconNode("envelope-o");
    },
  
    click() {
      if (this.attrs.canViewRawEmail) {
        this.sendWidgetAction("showRawEmail");
      }
    }
  });
  
  function showReplyTab(attrs, siteSettings) {
    return (
      attrs.replyToUsername &&
      (!attrs.replyDirectlyAbove || !siteSettings.suppress_reply_directly_above)
    );
  }
  
  createWidget("post-meta-data", {
    tagName: "div.topic-meta-data",
  
    settings: {
      displayPosterName: true
    },
  
    html(attrs) {
      let postInfo = [];
  
      if (attrs.isWhisper) {
        postInfo.push(
          h(
            "div.post-info.whisper",
            {
              attributes: { title: I18n.t("post.whisper") }
            },
            iconNode("eye-slash")
          )
        );
      }
  
      const lastWikiEdit =
        attrs.wiki && attrs.lastWikiEdit && new Date(attrs.lastWikiEdit);
      const createdAt = new Date(attrs.created_at);
      const date = lastWikiEdit ? dateNode(lastWikiEdit) : dateNode(createdAt);
      const attributes = {
        class: "post-date",
        href: attrs.shareUrl,
        "data-share-url": attrs.shareUrl,
        "data-post-number": attrs.post_number
      };
  
      if (lastWikiEdit) {
        attributes["class"] += " last-wiki-edit";
      }
  
      if (attrs.via_email) {
        postInfo.push(this.attach("post-email-indicator", attrs));
      }
  
      if (attrs.locked) {
        postInfo.push(this.attach("post-locked-indicator", attrs));
      }
  
      if (attrs.version > 1 || attrs.wiki) {
        postInfo.push(this.attach("post-edits-indicator", attrs));
      }
  
      if (attrs.multiSelect) {
        postInfo.push(this.attach("select-post", attrs));
      }
  
      if (showReplyTab(attrs, this.siteSettings)) {
        postInfo.push(this.attach("reply-to-tab", attrs));
      }
  
      postInfo.push(h("div.post-info.post-date", h("a", { attributes }, date)));
  
      postInfo.push(
        h(
          "div.read-state",
          {
            className: attrs.read ? "read" : null,
            attributes: {
              title: I18n.t("post.unread")
            }
          },
          iconNode("circle")
        )
      );
  
      let result = [];
      if (this.settings.displayPosterName) {
        result.push(this.attach("poster-name", attrs));
      }
      result.push(h("div.post-infos", postInfo));
  
      return result;
    }
  });
  
  createWidget("expand-hidden", {
    tagName: "a.expand-hidden",
  
    html() {
      return I18n.t("post.show_hidden");
    },
  
    click() {
      this.sendWidgetAction("expandHidden");
    }
  });
  
  createWidget("expand-post-button", {
    tagName: "button.btn.expand-post",
    buildKey: attrs => `expand-post-button-${attrs.id}`,
  
    defaultState() {
      return { loadingExpanded: false };
    },
  
    html(attrs, state) {
      if (state.loadingExpanded) {
        return I18n.t("loading");
      } else {
        return [I18n.t("post.show_full"), "..."];
      }
    },
  
    click() {
      this.state.loadingExpanded = true;
      this.sendWidgetAction("expandFirstPost");
    }
  });
  
  createWidget("post-contents", {
    buildKey: attrs => `post-contents-${attrs.id}`,
  
    defaultState() {
      return { expandedFirstPost: false, repliesBelow: [] };
    },
  
    buildClasses(attrs) {
      const classes = ["regular"];
      if (!this.state.repliesShown) {
        classes.push("contents");
      }
      if (showReplyTab(attrs, this.siteSettings)) {
        classes.push("avoid-tab");
      }
      return classes;
    },
  
    html(attrs, state) {
      let result = [new PostCooked(attrs, new DecoratorHelper(this))];
      result = result.concat(applyDecorators(this, "after-cooked", attrs, state));
  
      if (attrs.cooked_hidden) {
        result.push(this.attach("expand-hidden", attrs));
      }
  
      if (!state.expandedFirstPost && attrs.expandablePost) {
        result.push(this.attach("expand-post-button", attrs));
      }
  
      const extraState = { state: { repliesShown: !!state.repliesBelow.length } };
      result.push(this.attach("post-menu", attrs, extraState));
  
      const repliesBelow = state.repliesBelow;
      if (repliesBelow.length) {
        result.push(
          h("section.embedded-posts.bottom", [
            repliesBelow.map(p => {
              return this.attach("embedded-post", p, {
                model: this.store.createRecord("post", p)
              });
            }),
            this.attach("button", {
              title: "post.collapse",
              icon: "chevron-up",
              action: "toggleRepliesBelow",
              actionParam: "true",
              className: "btn collapse-up"
            })
          ])
        );
      }
  
      return result;
    },
  
    toggleRepliesBelow(goToPost = "false") {
      if (this.state.repliesBelow.length) {
        this.state.repliesBelow = [];
        if (goToPost === "true") {
          DiscourseURL.routeTo(
            `${this.attrs.topicUrl}/${this.attrs.post_number}`
          );
        }
        return;
      }
  
      const post = this.findAncestorModel();
      const topicUrl = post ? post.get("topic.url") : null;
      return this.store
        .find("post-reply", { postId: this.attrs.id })
        .then(posts => {
          this.state.repliesBelow = posts.map(p => {
            p.shareUrl = `${topicUrl}/${p.post_number}`;
            return transformBasicPost(p);
          });
        });
    },
  
    expandFirstPost() {
      const post = this.findAncestorModel();
      return post.expand().then(() => (this.state.expandedFirstPost = true));
    }
  });
  
  createWidget("post-body", {
    tagName: "div.topic-body.clearfix",
  
    html(attrs, state) {
      const postContents = this.attach("post-contents", attrs);
      let result = [this.attach("post-meta-data", attrs)];
      result = result.concat(
        applyDecorators(this, "after-meta-data", attrs, state)
      );
      result.push(postContents);
      result.push(this.attach("actions-summary", attrs));
      result.push(this.attach("post-links", attrs));
      if (attrs.showTopicMap) {
        result.push(this.attach("topic-map", attrs));
      }
  
      return result;
    }
  });
  
  createWidget("post-article", {
    tagName: "article.boxed.onscreen-post",
    buildKey: attrs => `post-article-${attrs.id}`,
  
    defaultState() {
      return { repliesAbove: [] };
    },
  
    buildId(attrs) {
      return `post_${attrs.post_number}`;
    },
  
    buildClasses(attrs) {
      let classNames = [];
      if (attrs.via_email) {
        classNames.push("via-email");
      }
      if (attrs.isAutoGenerated) {
        classNames.push("is-auto-generated");
      }
      return classNames;
    },
  
    buildAttributes(attrs) {
      return { "data-post-id": attrs.id, "data-user-id": attrs.user_id };
    },
  
    html(attrs, state) {
      const rows = [h("a.tabLoc", { attributes: { href: "" } })];
      if (state.repliesAbove.length) {
        const replies = state.repliesAbove.map(p => {
          return this.attach("embedded-post", p, {
            model: this.store.createRecord("post", p),
            state: { above: true }
          });
        });
  
        rows.push(
          h(
            "div.row",
            h("section.embedded-posts.top.topic-body.offset2", [
              this.attach("button", {
                title: "post.collapse",
                icon: "chevron-down",
                action: "toggleReplyAbove",
                actionParam: "true",
                className: "btn collapse-down"
              }),
              replies
            ])
          )
        );
      }
  
      rows.push(
        h("div.row", [
          this.attach("post-avatar", attrs),
          this.attach("post-body", attrs)
        ])
      );
      return rows;
    },
  
    _getTopicUrl() {
      const post = this.findAncestorModel();
      return post ? post.get("topic.url") : null;
    },
  
    toggleReplyAbove(goToPost = "false") {
      const replyPostNumber = this.attrs.reply_to_post_number;
  
      // jump directly on mobile
      if (this.attrs.mobileView) {
        const topicUrl = this._getTopicUrl();
        if (topicUrl) {
          DiscourseURL.routeTo(`${topicUrl}/${replyPostNumber}`);
        }
        return Ember.RSVP.Promise.resolve();
      }
  
      if (this.state.repliesAbove.length) {
        this.state.repliesAbove = [];
        if (goToPost === "true") {
          DiscourseURL.routeTo(
            `${this.attrs.topicUrl}/${this.attrs.post_number}`
          );
        }
        return Ember.RSVP.Promise.resolve();
      } else {
        const topicUrl = this._getTopicUrl();
        return this.store
          .find("post-reply-history", { postId: this.attrs.id })
          .then(posts => {
            this.state.repliesAbove = posts.map(p => {
              p.shareUrl = `${topicUrl}/${p.post_number}`;
              return transformBasicPost(p);
            });
          });
      }
    }
  });
  
  let addPostClassesCallbacks = null;
  export function addPostClassesCallback(callback) {
    addPostClassesCallbacks = addPostClassesCallbacks || [];
    addPostClassesCallbacks.push(callback);
  }
  
  export default createWidget("post", {
    buildKey: attrs => `post-${attrs.id}`,
    shadowTree: true,
  
    buildAttributes(attrs) {
      return attrs.height
        ? { style: `min-height: ${attrs.height}px` }
        : undefined;
    },
  
    buildId(attrs) {
      return attrs.cloaked ? `post_${attrs.post_number}` : undefined;
    },
  
    buildClasses(attrs) {
      if (attrs.cloaked) {
        return "cloaked-post";
      }
      const classNames = ["topic-post", "clearfix"];
  
      if (attrs.id === -1 || attrs.isSaving) {
        classNames.push("staged");
      }
      if (attrs.selected) {
        classNames.push("selected");
      }
      if (attrs.topicOwner) {
        classNames.push("topic-owner");
      }
      if (attrs.hidden) {
        classNames.push("post-hidden");
      }
      if (attrs.deleted) {
        classNames.push("deleted");
      }
      if (attrs.primary_group_name) {
        classNames.push(`group-${attrs.primary_group_name}`);
      }
      if (attrs.wiki) {
        classNames.push(`wiki`);
      }
      if (attrs.isWhisper) {
        classNames.push("whisper");
      }
      if (attrs.isModeratorAction || (attrs.isWarning && attrs.firstPost)) {
        classNames.push("moderator");
      } else {
        classNames.push("regular");
      }
      if (addPostClassesCallbacks) {
        for (let i = 0; i < addPostClassesCallbacks.length; i++) {
          let pluginClasses = addPostClassesCallbacks[i].call(this, attrs);
          if (pluginClasses) {
            classNames.push.apply(classNames, pluginClasses);
          }
        }
      }
      return classNames;
    },
  
    html(attrs) {
      if (attrs.cloaked) {
        return "";
      }
  
      return this.attach("post-article", attrs);
    },
  
    toggleLike() {
      const post = this.model;
      const likeAction = post.get("likeAction");
  
      if (likeAction && likeAction.get("canToggle")) {
        return likeAction
          .togglePromise(post)
          .then(result => this._warnIfClose(result));
      }
    },
  
    _warnIfClose(result) {
      if (!result || !result.acted) {
        return;
      }
  
      const kvs = this.keyValueStore;
      const lastWarnedLikes = kvs.get("lastWarnedLikes");
  
      // only warn once per day
      const yesterday = new Date().getTime() - 1000 * 60 * 60 * 24;
      if (lastWarnedLikes && parseInt(lastWarnedLikes) > yesterday) {
        return;
      }
  
      const { remaining, max } = result;
      const threshold = Math.ceil(max * 0.1);
      if (remaining === threshold) {
        bootbox.alert(I18n.t("post.few_likes_left"));
        kvs.set({ key: "lastWarnedLikes", value: new Date().getTime() });
      }
    },
  
    undoPostAction(typeId) {
      const post = this.model;
      return post
        .get("actions_summary")
        .findBy("id", typeId)
        .undo(post);
    },
  
    deferPostActionFlags(typeId) {
      const post = this.model;
      return post
        .get("actions_summary")
        .findBy("id", typeId)
        .deferFlags(post);
    }
  });
  