<template>
  <view>
    <view>
      <view class="chat_footer">

        <view class="footer_action_area">
          <image v-if="inputBox"
              @click.prevent="updateInput"
              src="@/static/images/chating_footer_recording.png"
              alt=""
              srcset=""
          />

		  <image v-if="!inputBox"
              @click.prevent="updateInput"
              src="@/static/images/chating_footer_audio_recording.png"
              alt=""
              srcset=""
          />
        </view>

        <view class="input_content" v-if="inputBox">
          <CustomEditor class="custom_editor" ref="customEditor" @ready="editorReady" @focus="editorFocus"
                        @blur="editorBlur" @input="editorInput"/>
        </view>

        <view class="input_content"
              v-if="!inputBox"
              style="position:relative;"
        >
          <!-- 录音提示区域 -->
          <view v-if="isRecording"
                style="position:absolute;left:50%;top:-120rpx;transform:translateX(-50%);z-index:10;display:flex;flex-direction:column;align-items:center;">
            <view :style="{
              background: willCancel ? 'rgba(255,80,80,0.95)' : 'rgba(0,0,0,0.85)',
              color: '#fff',
              borderRadius: '12rpx',
              padding: '18rpx 32rpx',
              fontSize: '28rpx',
              minWidth: '260rpx',
              textAlign: 'center',
              marginBottom: '10rpx',
            }">
              <text v-if="willCancel">松开手指，取消发送</text>
              <text v-else>正在讲话，已录制 {{recordingTime}} 秒，松开发送</text>
            </view>
          </view>
          <!-- 蒙版 -->
          <view v-if="isRecording" style="position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,0.08);z-index:5;border-radius:16rpx;"></view>
          <button
            class="record_btn"
            @touchstart="startRecord"
            @touchend="stopRecord"
            @touchcancel="cancelRecord"
            @touchmove="moveRecord"
            style="width:100%;height:100%;background:transparent;border:none;outline:none;display:flex;align-items:center;justify-content:center;z-index:20;position:relative;"
          >
            <text v-if="!isRecording">按住说话</text>
            <text v-else :style="willCancel ? 'color:#ff5050;' : 'color:#4a9cfc;'">{{ willCancel ? '松开手指，取消发送' : '正在说话，松开发送' }}</text>
          </button>
        </view>

        <view class="footer_action_area">
          <image
            class="emoji_action"
            v-if="inputBox && !showEmojiPicker"
            @click.prevent="toggleEmojiPicker"
            src="@/static/images/chating_footer_emoji.png"
            alt=""
            srcset=""
          />
          <image
            class="emoji_action"
            v-if="inputBox && showEmojiPicker"
            @click.prevent="closeEmojiAndFocusInput"
            src="@/static/images/chating_footer_audio_recording.png"
            alt=""
            srcset=""
          />
          <image
              v-show="!hasContent"
              @click.prevent="updateActionBar"
              src="@/static/images/chating_footer_add.png"
              alt=""
              srcset=""
          />
          <image v-show="hasContent" @touchend.prevent="sendTextMessage" src="@/static/images/send_btn.png"
                 alt="" srcset=""/>
        </view>
      </view>
      <chating-action-bar @sendMessage="sendMessage" @prepareMediaMessage="prepareMediaMessage"
                          v-show="actionBarVisible"/>
      <u-action-sheet :safeAreaInsetBottom="true" round="12" :actions="actionSheetMenu" @select="selectClick"
                      :closeOnClickOverlay="true" :closeOnClickAction="true" :show="showActionSheet"
                      @close="showActionSheet = false">
      </u-action-sheet>
      <!-- Emoji 选择面板 -->
      <view v-if="showEmojiPicker">
        <view class="emoji-mask" @touchstart="showEmojiPicker = false" style="position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:998;"></view>
        <view class="emoji-picker" style="position:relative;z-index:999;">
          <EmojiPicker @select="onEmojiSelect" />
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import {
  mapGetters,
  mapActions
} from "vuex";
import {
  getPurePath,
  html2Text
} from "@/util/common";
import {
  offlinePushInfo
} from "@/util/imCommon";
import {
  ChatingFooterActionTypes,
  UpdateMessageTypes,
} from "@/constant";
import IMSDK, {
  IMMethods,
  MessageStatus,
  MessageType,
} from "openim-uniapp-polyfill";
import UParse from "@/components/gaoyia-parse/parse.vue";
import CustomEditor from "./CustomEditor.vue";
import ChatingActionBar from "./ChatingActionBar.vue";
import EmojiPicker from '@/components/EmojiPicker/index.vue';

const needClearTypes = [MessageType.TextMessage];

const albumChoose = [{
  name: "图片",
  type: ChatingFooterActionTypes.Album,
  idx: 0,
},
  {
    name: "拍照",
    type: ChatingFooterActionTypes.Camera,
    idx: 1,
  },
];

export default {
  components: {
    CustomEditor,
    ChatingActionBar,
    UParse,
    EmojiPicker,
  },
  props: {
    footerOutsideFlag: Number,
  },
  data() {
    return {
      inputBox: true,
      customEditorCtx: null,
      inputHtml: "",
      actionBarVisible: false,
      isInputFocus: false,
      actionSheetMenu: [],
      showActionSheet: false,
      isRecording: false,
      willCancel: false,
      recordingTime: 0,
      recordingTimer: null,
      showEmojiPicker: false,
      recorderManager: null,
      recordFilePath: '',
      recordFileDuration: 0,
    };
  },
  computed: {
    ...mapGetters([
      "storeCurrentConversation",
      "storeCurrentGroup",
      "storeBlackList",
    ]),
    hasContent() {
      return html2Text(this.inputHtml) !== "";
    },
  },
  watch: {
    footerOutsideFlag(newVal) {
      this.onClickActionBarOutside();
    },
  },
  mounted() {
    this.setKeyboardListener();
    document.addEventListener('plusready', function() {
      // plus 相关代码
    });
  },
  beforeDestroy() {
    this.disposeKeyboardListener();
  },
  methods: {
    updateInput() {
      this.inputBox = !this.inputBox;
      this.showEmojiPicker = false;
    },
    startRecord(e) {
      this.isRecording = true;
      this.willCancel = false;
      this.recordingTime = 0;
      if (this.recordingTimer) clearInterval(this.recordingTimer);
      this.recordingTimer = setInterval(() => {
        this.recordingTime++;
      }, 1000);
      // 录音开始
      if (!this.recorderManager) {
        this.recorderManager = uni.getRecorderManager();
        this.recorderManager.onStop(this.onRecordStop);
      }
      this.recordFilePath = '';
      this.recordFileDuration = 0;
      this.recorderManager.start({ format: 'mp3' });
    },
    stopRecord(e) {
      if (this.recordingTimer) clearInterval(this.recordingTimer);
      this.recordingTimer = null;
      this.isRecording = false;
      if (this.recorderManager) {
        this.recorderManager.stop();
      }
      this._startY = null;
    },
    cancelRecord(e) {
      if (this.recordingTimer) clearInterval(this.recordingTimer);
      this.recordingTimer = null;
      this.isRecording = false;
      this.willCancel = false;
      this.recordingTime = 0;
      if (this.recorderManager) {
        this.recorderManager.stop();
      }
      this._startY = null;
    },
    moveRecord(e) {
      // 判断手指是否上滑，通常通过e.touches[0].clientY与起始Y比较
      if (!this.isRecording) return;
      const touch = e.touches[0];
      if (!this._startY && touch) {
        this._startY = touch.clientY;
      }
      if (touch && this._startY) {
        // 上滑距离大于40px则判定为取消
        this.willCancel = (this._startY - touch.clientY) > 40;
      }
    },

    ...mapActions("message", ["pushNewMessage", "updateOneMessage"]),
    async createTextMessage() {
      let message = "";
      const text = html2Text(this.inputHtml);
      message = await IMSDK.asyncApi(
          IMMethods.CreateTextMessage,
          IMSDK.uuid(),
          text
      );
      return message;
    },
    async sendTextMessage() {
      if (!this.hasContent) return;
      const message = await this.createTextMessage();
      this.sendMessage(message);
    },
    sendMessage(message) {
      this.pushNewMessage(message);
      if (needClearTypes.includes(message.contentType)) {
        this.customEditorCtx.clear();
      }
      this.$emit("scrollToBottom");
      IMSDK.asyncApi(IMMethods.SendMessage, IMSDK.uuid(), {
        recvID: this.storeCurrentConversation.userID,
        groupID: this.storeCurrentConversation.groupID,
        message,
        offlinePushInfo,
      })
          .then(({
                   data
                 }) => {
            this.updateOneMessage({
              message: data,
              isSuccess: true,
            });
          })
          .catch(({
                    data,
                    errCode,
                    errMsg
                  }) => {
            this.updateOneMessage({
              message: data,
              type: UpdateMessageTypes.KeyWords,
              keyWords: [{
                key: "status",
                value: MessageStatus.Failed,
              },
                {
                  key: "errCode",
                  value: errCode,
                },
              ],
            });
          });
    },

    // action
    onClickActionBarOutside() {
      if (this.actionBarVisible) {
        this.actionBarVisible = false;
      }
    },
    updateActionBar() {
      this.actionBarVisible = !this.actionBarVisible;
      this.showEmojiPicker = false;
    },
    editorReady(e) {
      this.customEditorCtx = e.context;
      this.customEditorCtx.clear();
    },
    editorFocus() {
      this.isInputFocus = true;
      this.showEmojiPicker = false;
      this.$emit("scrollToBottom");
    },
    editorBlur() {
      this.isInputFocus = false;
    },
    editorInput(e) {
      this.inputHtml = e.detail.html;
    },
    prepareMediaMessage(type) {
      if (type === ChatingFooterActionTypes.Album) {
        this.actionSheetMenu = [...albumChoose];
        this.showActionSheet = true;
      } else if (type === ChatingFooterActionTypes.File) {
        this.chooseFileAndSend();
      }
    },
    async chooseFileAndSend() {
      if (!uni.chooseMessageFile) {
        return;
      }
      uni.chooseMessageFile({
        count: 1,
        type: 'file',
        success: async (res) => {
          const file = res.tempFiles[0];
          try {
            const nameIdx = file.name.lastIndexOf("/") + 1;
            const fileName = file.name.slice(nameIdx);
            const typeIdx = file.name.lastIndexOf(".") + 1;
            const fileType = file.name.slice(typeIdx);
            const { data: { url } } = await IMSDK.asyncApi(IMMethods.UploadFile, IMSDK.uuid(), {
              filepath: file.path,
              name: fileName,
              contentType: fileType,
              uuid: IMSDK.uuid(),
            });
            // 创建文件消息
            const message = await IMSDK.asyncApi(IMMethods.CreateFileMessage, IMSDK.uuid(), {
              fileName: fileName,
              fileSize: file.size,
              sourceUrl: url,
            });
            this.sendMessage(message);
          } catch (e) {
          }
        },
        fail: function (err) {
        },
      });
    },

    // from comp
    batchCreateImageMesage(paths) {
      paths.forEach(async (path) => {
        const message = await IMSDK.asyncApi(
            IMMethods.CreateImageMessageFromFullPath,
            IMSDK.uuid(),
            getPurePath(path)
        );
        this.sendMessage(message);
      });
    },
    selectClick({
                  idx
                }) {
      if (idx === 0) {
        this.chooseOrShotImage(["album"]).then((paths) =>
            this.batchCreateImageMesage(paths)
        );
      } else {
        this.chooseOrShotImage(["camera"]).then((paths) =>
            this.batchCreateImageMesage(paths)
        );
      }
    },
    chooseOrShotImage(sourceType) {
      return new Promise((resolve, reject) => {
        uni.chooseImage({
          count: 9,
          sizeType: ["compressed"],
          sourceType,
          success: function ({
                               tempFilePaths
                             }) {
            resolve(tempFilePaths);
          },
          fail: function (err) {
            reject(err);
          },
        });
      });
    },

    // keyboard
    keyboardChangeHander({
                           height
                         }) {
      if (height > 0) {
        if (this.actionBarVisible) {
          this.actionBarVisible = false;
        }
      }
    },
    setKeyboardListener() {
      uni.onKeyboardHeightChange(this.keyboardChangeHander);
    },
    disposeKeyboardListener() {
      uni.offKeyboardHeightChange(this.keyboardChangeHander);
    },
    toggleEmojiPicker() {
      this.showEmojiPicker = !this.showEmojiPicker;
      if (!this.showEmojiPicker && this.$refs.customEditor && this.$refs.customEditor.editorCtx) {
        // 关闭emoji面板时再focus
        this.$refs.customEditor.editorCtx.focus();
      }
    },
    closeEmojiAndFocusInput() {
      this.showEmojiPicker = false;
      // 只在这里主动focus
      if (this.$refs.customEditor && this.$refs.customEditor.editorCtx) {
        this.$refs.customEditor.editorCtx.focus();
      }
    },
    onEmojiSelect(emoji) {
      this.inputHtml += emoji;
      if (this.$refs.customEditor && this.$refs.customEditor.editorCtx) {
        this.$refs.customEditor.editorCtx.setContents({
          html: this.inputHtml
        });
      }
      // 不做任何focus/blur
    },
    async onRecordStop(res) {
      let tempFilePath = res.tempFilePath;
      let fileName = tempFilePath.split('/').pop();
      let fileType = fileName.split('.').pop();
      let uuid = IMSDK.uuid();
      let duration = this.recordingTime;
      if (!duration || isNaN(duration) || duration < 1) {
        this.recordingTime = 0;
        return;
      }
      // 先保存到本地
      uni.saveFile({
        tempFilePath,
        success: (saveRes) => {
          let savedFilePath = saveRes.savedFilePath;
          // 用 plus.io 转换为原生绝对路径
          if (typeof plus !== 'undefined') {
            plus.io.resolveLocalFileSystemURL(savedFilePath, (entry) => {
              IMSDK.asyncApi('uploadFile', uuid, {
                name: fileName,
                contentType: fileType,
                uuid: uuid,
                filepath: entry.fullPath
              })
              .then(({ data }) => {
                let sourceUrl = data.url;
                IMSDK.asyncApi('createSoundMessageByURL', IMSDK.uuid(), {
                  uuid: uuid,
                  soundPath: entry.fullPath,
                  sourceUrl: sourceUrl,
                  dataSize: res.fileSize || 0,
                  duration: duration,
                  soundType: fileType
                })
                .then((message) => {
                  IMSDK.asyncApi('sendMessageNotOss', IMSDK.uuid(), {
                    recvID: this.storeCurrentConversation.userID,
                    groupID: this.storeCurrentConversation.groupID,
                    message: message,
                    offlinePushInfo: {
                      title: '你有新消息',
                      desc: '新消息',
                      ex: '',
                      iOSPushSound: '+1',
                      iOSBadgeCount: true,
                    }
                  })
                  .then(({ data }) => {
                    // 1. 本地新增消息
                    this.pushNewMessage(message);
                    // 2. 更新消息状态
                    this.updateOneMessage({
                      message: data,
                      isSuccess: true,
                    });
                    this.$emit("scrollToBottom");
                  })
                  .catch(({ errCode, errMsg }) => {
                    // 发送失败时也要更新消息状态为失败
                    this.updateOneMessage({
                      message: message,
                      type: UpdateMessageTypes.KeyWords,
                      keyWords: [
                        { key: "status", value: MessageStatus.Failed },
                        { key: "errCode", value: errCode },
                      ],
                    });
                  });
                })
                .catch(() => {
                  // 忽略错误提示
                });
              })
              .catch(() => {
                // 忽略错误提示
              });
            }, () => {
              // 忽略路径转换失败
            });
          }
        },
        fail: () => {
          // 忽略保存失败
        }
      });
      this.recordingTime = 0;
    },
  },
};
</script>

<style lang="scss" scoped>
.custom_editor {
  img {
    vertical-align: sub;
  }
}

.forbidden_footer {
  width: 100%;
  height: 112rpx;
  color: #8e9ab0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  background: #f0f2f6;
}

.chat_footer {
  display: flex;
  align-items: center;
  // background-color: #e9f4ff;
  background: #f0f2f6;
  // height: 50px;
  max-height: 120px;
  padding: 24rpx 20rpx;

  .input_content {
    flex: 1;
    min-height: 30px;
    max-height: 120px;
    margin: 0 24rpx;
    border-radius: 16rpx;
    position: relative;

    .record_btn {
      // background-color: #3c9cff;
      background: #fff;
      color: black;
      height: 30px;
      font-size: 24rpx;
    }
  }

  .quote_message {
    @include vCenterBox();
    justify-content: space-between;
    margin-top: 12rpx;
    padding: 8rpx;
    // padding-top: 20rpx;
    border-radius: 6rpx;
    background-color: #fff;
    color: #666;

    .content {
      /deep/ uni-view {
        @include ellipsisWithLine(2);
      }
    }
  }

  .footer_action_area {
    display: flex;
    align-items: center;

    .emoji_action {
      margin-right: 24rpx;
    }

    image {
      width: 26px;
      height: 26px;
    }
  }

  .send_btn {
    height: 30px;
    line-height: 30px;
    background-color: #4a9cfc;
    padding: 0 8px;
    border-radius: 4px;
    color: #fff;
  }
}

.emoji-mask {
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  background: transparent;
  z-index: 998;
}
.emoji-picker {
  position: relative;
  z-index: 999;
}
</style>