import MessageContentType from "../messages/messageContentType";
import wfc from "../client/wfc";
import MediaMessageContent from "../messages/mediaMessageContent";
import { stringValue } from "../util/longUtil";
import Message from "../messages/message";
import Conversation from "../model/conversation";
import Long from "long";
import { compare } from "../../wfc/util/longUtil";
import MessagePayload from "../messages/messagePayload";
import { isElectron } from "../../platform";
import ArticlesMessageContent from "./articlesMessageContent";
import MessageContentMediaType from "./messageContentMediaType";

export default class CompositeMessageContent extends MediaMessageContent {
  title = "";
  messages = [];
  // web 端有效，仅仅是用来标识 mediaCompositeMessage 是否已加载
  loaded = false;

  constructor() {
    super(MessageContentType.Composite_Message, MessageContentMediaType.General, "");
  }

  setMessages(msgs) {
    this.messages = [];
    msgs.forEach((m) => {
      if (m.messageContent instanceof ArticlesMessageContent) {
        let linkMessageContents = m.messageContent.toLinkMessageContent();
        linkMessageContents.forEach((lm) => {
          let msg = Object.assign(new Message(), m);
          msg.messageContent = lm;
          this.messages.push(msg);
        });
      } else {
        this.messages.push(m);
      }
    });
    this.messages = this.messages.sort((m1, m2) => {
      return compare(m1.messageUid, m2.messageUid);
    });
  }

  digest(message) {
    return "[聊天记录]" + this.title;
  }

  encode() {
    let payload = super.encode();
    payload.content = this.title;
    let arr = [];
    let binArr;
    let size = 0;
    this.messages.forEach((msg) => {
      let msgPayload = msg.messageContent.encode();
      let o = {
        uid: stringValue(msg.messageUid),
        type: msg.conversation.type,
        target: msg.conversation.target,
        line: msg.conversation.line,
        from: msg.from,
        tos: msg.to,
        direction: msg.direction,
        status: msg.status,
        serverTime: stringValue(msg.timestamp),
        ctype: msgPayload.type,
        csc: msgPayload.searchableContent,
        cpc: msgPayload.pushContent,
        cpd: msgPayload.pushData,
        cc: msgPayload.content,
        cmt: msgPayload.mentionedType,
        cmts: msgPayload.mentionedTargets,
        ce: msgPayload.extra,
      };
      if (msgPayload.searchableContent) {
        payload.searchableContent = payload.searchableContent + msgPayload.searchableContent + " ";
      }

      if (msgPayload.binaryContent) {
        o.cbc = msgPayload.binaryContent;
      }
      if (msg.messageContent instanceof MediaMessageContent) {
        o.mt = msg.messageContent.mediaType;
        o.mru = msg.messageContent.remotePath;
      }

      if (!binArr) {
        size += JSON.stringify(o).length;
        if (size > 20480 && arr.length > 0) {
          binArr = arr.map((value) => value);
        }
      }

      arr.push(o);
    });

    let obj;
    if (binArr && !this.file) {
      obj = {
        ms: arr,
      };
      let str = JSON.stringify(obj);
      str = str.replace(/"uid":"([0-9]+)"/, '"uid":$1');
      str = str.replace(/"serverTime":"([0-9]+)"/, '"serverTime":$1');

      let blob = new Blob([str]);
      let fileName = "wcf-" + new Date().getTime() + ".data";
      this.file = new File([blob], fileName);
      if (isElectron()) {
        this.localPath = require("tmp").tmpNameSync() + fileName;
        require("fs").writeFileSync(this.localPath, str);
        payload.localMediaPath = this.localPath;
        payload.mediaType = MessageContentType.File;
      }
      obj = {
        ms: binArr,
      };
    } else {
      if (binArr) {
        obj = {
          ms: binArr,
        };
      } else {
        obj = {
          ms: arr,
        };
      }
    }

    let str = JSON.stringify(obj);
    str = str.replace(/"uid":"([0-9]+)"/, '"uid":$1');
    str = str.replace(/"serverTime":"([0-9]+)"/, '"serverTime":$1');

    payload.binaryContent = wfc.utf8_to_b64(str);
    return payload;
  }

  decode(payload) {
    super.decode(payload);

    this.title = payload.content;
    let str;
    if (this.file) {
      // web
      let fileReader = new FileReader();
      fileReader.onload((ev) => {
        this._decodeMessages(ev.target.result);
      });
      fileReader.readAsBinaryString(this.file);
    } else if (this.localPath) {
      // electron
      if (isElectron()) {
        const fs = require("fs");
        if (fs.existsSync(this.localPath)) {
          const buffer = fs.readFileSync(this.localPath);
          str = buffer.toString();
          this._decodeMessages(str);
        } else {
          console.log("media composite message not downloaded", this.remotePath);
        }
      }
    }

    if (!str) {
      str = wfc.b64_to_utf8(payload.binaryContent);
      this._decodeMessages(str);
    }
  }

  _decodeMessages(str) {
    if (this.loaded) {
      return;
    }
    this.messages = [];
    // FIXME node 环境，decodeURIComponent 方法，有时候会在最后添加上@字符，目前尚未找到原因，先规避
    str = str.substring(0, str.lastIndexOf("}") + 1);
    str = str.replace(/"uid":([0-9]+)/g, '"uid":"$1"');
    str = str.replace(/"serverTime":([0-9]+)/g, '"serverTime":"$1"');
    let obj = JSON.parse(str);
    obj.ms.forEach((o) => {
      let conv = new Conversation(o.type, o.target, o.line);
      let msg = new Message();
      msg.messageUid = Long.fromValue(o.uid);
      msg.conversation = conv;
      msg.from = o.from;
      msg.to = o.tos;
      msg.direction = o.direction;
      msg.status = o.status;
      msg.timestamp = Long.fromValue(o.serverTime);

      let payload = new MessagePayload();
      payload.type = o.ctype;
      payload.searchableContent = o.csc;
      payload.pushContent = o.cpc;
      payload.pushData = o.cpd;
      payload.content = o.cc;
      payload.mentionedType = o.cmt;
      payload.mentionedTargets = o.cmts;
      payload.extra = o.ce;

      payload.binaryContent = o.cbc;
      payload.mediaType = o.mt;
      payload.remoteMediaUrl = o.mru;

      msg.messageContent = Message.messageContentFromMessagePayload(payload, msg.from);
      this.messages.push(msg);
    });
    console.log("cp ms", this.messages);
  }
}
