import uuid from 'uuid/v4';
import { ensureArray, decodeDate, getTime } from '../utils';

/**
 * 消息状态枚举
 * @enum {Symbol}
 * @since 3.2.0
 * @memberof module:leancloud-realtime
 */
const MessageStatus = {
  /** 初始状态、未知状态 */
  NONE: Symbol('none'),
  /** 正在发送 */
  SENDING: Symbol('sending'),
  /** 已发送 */
  SENT: Symbol('sent'),
  /** 已送达 */
  DELIVERED: Symbol('delivered'),
  /** 发送失败 */
  FAILED: Symbol('failed'),
};
Object.freeze(MessageStatus);

const rMessageStatus = {
  [MessageStatus.NONE]: true,
  [MessageStatus.SENDING]: true,
  [MessageStatus.SENT]: true,
  [MessageStatus.DELIVERED]: true,
  [MessageStatus.READ]: true,
  [MessageStatus.FAILED]: true,
};

export { MessageStatus };
export default class Message {
  /**
   * @implements AVMessage
   * @param  {Object|String|ArrayBuffer} content 消息内容
   */
  constructor(content) {
    Object.assign(
      this,
      { content },
      {
        /**
         * @type {String}
         * @memberof Message#
         */
        id: uuid(),
        /**
         * 消息所在的 conversation id
         * @memberof Message#
         * @type {String?}
         */
        cid: null,
        /**
         * 消息发送时间
         * @memberof Message#
         * @type {Date}
         */
        timestamp: new Date(),
        /**
         * 消息发送者
         * @memberof Message#
         * @type {String}
         */
        from: undefined,
        /**
         * 消息提及的用户
         * @since 4.0.0
         * @memberof Message#
         * @type {String[]}
         */
        mentionList: [],
        /**
         * 消息是否提及了所有人
         * @since 4.0.0
         * @memberof Message#
         * @type {Boolean}
         */
        mentionedAll: false,
        _mentioned: false,
      }
    );
    this._setStatus(MessageStatus.NONE);
  }

  /**
   * 将当前消息的内容序列化为 JSON 对象
   * @private
   * @return {Object}
   */
  getPayload() {
    return this.content;
  }

  _toJSON() {
    const {
      id,
      cid,
      from,
      timestamp,
      deliveredAt,
      updatedAt,
      mentionList,
      mentionedAll,
      mentioned,
    } = this;
    return {
      id,
      cid,
      from,
      timestamp,
      deliveredAt,
      updatedAt,
      mentionList,
      mentionedAll,
      mentioned,
    };
  }

  /**
   * 返回 JSON 格式的消息
   * @return {Object} 返回值是一个 plain Object
   */
  toJSON() {
    return {
      ...this._toJSON(),
      data: this.content,
    };
  }

  /**
   * 返回 JSON 格式的消息,与 toJSON 不同的是,该对象包含了完整的信息,可以通过 {@link IMClient#parseMessage} 反序列化。
   * @return {Object} 返回值是一个 plain Object
   * @since 4.0.0
   */
  toFullJSON() {
    const {
      content,
      id,
      cid,
      from,
      timestamp,
      deliveredAt,
      _updatedAt,
      mentionList,
      mentionedAll,
    } = this;
    return {
      data: content,
      id,
      cid,
      from,
      timestamp: getTime(timestamp),
      deliveredAt: getTime(deliveredAt),
      updatedAt: getTime(_updatedAt),
      mentionList,
      mentionedAll,
    };
  }

  /**
   * 消息状态,值为 {@link module:leancloud-realtime.MessageStatus} 之一
   * @type {Symbol}
   * @readonly
   * @since 3.2.0
   */
  get status() {
    return this._status;
  }

  _setStatus(status) {
    if (!rMessageStatus[status]) {
      throw new Error('Invalid message status');
    }
    this._status = status;
  }

  get timestamp() {
    return this._timestamp;
  }

  set timestamp(value) {
    this._timestamp = decodeDate(value);
  }

  /**
   * 消息送达时间
   * @type {?Date}
   */
  get deliveredAt() {
    return this._deliveredAt;
  }

  set deliveredAt(value) {
    this._deliveredAt = decodeDate(value);
  }

  /**
   * 消息修改或撤回时间,可以通过比较其与消息的 timestamp 是否相等判断消息是否被修改过或撤回过。
   * @type {Date}
   * @since 3.5.0
   */
  get updatedAt() {
    return this._updatedAt || this.timestamp;
  }

  set updatedAt(value) {
    this._updatedAt = decodeDate(value);
  }

  /**
   * 当前用户是否在该消息中被提及
   * @type {Boolean}
   * @readonly
   * @since 4.0.0
   */
  get mentioned() {
    return this._mentioned;
  }

  _updateMentioned(client) {
    this._mentioned =
      this.from !== client &&
      (this.mentionedAll || this.mentionList.indexOf(client) > -1);
  }

  /**
   * 获取提及用户列表
   * @since 4.0.0
   * @return {String[]} 提及用户的 id 列表
   */
  getMentionList() {
    return this.mentionList;
  }

  /**
   * 设置提及用户列表
   * @since 4.0.0
   * @param {String[]} clients 提及用户的 id 列表
   * @return {this} self
   */
  setMentionList(clients) {
    this.mentionList = ensureArray(clients);
    return this;
  }

  /**
   * 设置是否提及所有人
   * @since 4.0.0
   * @param {Boolean} [value=true]
   * @return {this} self
   */
  mentionAll(value = true) {
    this.mentionedAll = Boolean(value);
    return this;
  }

  /**
   * 判断给定的内容是否是有效的 Message,
   * 该方法始终返回 true
   * @private
   * @returns {Boolean}
   * @implements AVMessage.validate
   */
  static validate() {
    return true;
  }

  /**
   * 解析处理消息内容
   * <pre>
   * 如果子类提供了 message,返回该 message
   * 如果没有提供,将 json 作为 content 实例化一个 Message
   * @private
   * @param  {Object}  json    json 格式的消息内容
   * @param  {Message} message 子类提供的 message
   * @return {Message}
   * @implements AVMessage.parse
   */
  static parse(json, message) {
    return message || new this(json);
  }
}