<template>
    <view class="ask-template-wrapper">
        <view class="ask-item" v-for="(item, index) in askList()" :key="index">

            <s-divider></s-divider>

            <view class="title">
                <view style="display: flex;align-items: center;">
                    <h4>问答{{ index + 1 }}</h4>
                    <view @click="addTemplate" v-if="index === 0 && showAskTemplate"
                        style="margin-left: 10px;font-size: 12px;color: #409eff;">添加模板</view>
                </view>
                <view class="title-right">
                    <s-icon size="18px" @click="deleteItem(item)" name="trash" color="rgb(216,19,7)"
                        v-if="showEditBtn"></s-icon>
                    <s-icon size="16px" @click="addItem()" style="margin-left: 5px;" name="plus-circle" v-if="showEditBtn"
                        color="#409eff"></s-icon>
                </view>
            </view>
            <view class="question">
                <s-textarea @input="val => { handleInput(val, item, 1) }" :value="getKeyContent(item, 1)" :maxlength="-1"
                    placeholder="请输入问题" autoHeight :disabled="!showEditBtn"></s-textarea>

                <template v-if="showEditBtn">
                    <view class="icon-class" style="display: flex;align-items: center;"
                        v-if="recording && (currentIndex == index) && (currentType === 1)">
                        <s-icon color="rgb(216, 19, 7)" @click="startAudio(item, index, 1)" size="18px"
                            name="mic-off"></s-icon>

                        <text @click="endRecording" style="font-size: 10px;color: rgb(216, 19, 7);">结束录音</text>
                    </view>

                    <s-icon v-else="!recording" color="#409EFF" @click="startAudio(item, index, 1)" size="18px"
                        class="icon-class" name="mic"></s-icon>

                </template>




            </view>

            <view class="answer">


                <s-textarea @input="val => { handleInput(val, item, 2) }" :value="getKeyContent(item, 2)" :maxlength="-1"
                    placeholder="请输入回答" :disabled="!showEditBtn" autoHeight></s-textarea>

                <template v-if="showEditBtn">

                    <view class="icon-class" style="display: flex;align-items: center;"
                        v-if="recording && (currentIndex == index) && (currentType === 2)">
                        <s-icon color="rgb(216, 19, 7)" @click="startAudio(item, index, 1)" size="18px"
                            name="mic-off"></s-icon>

                        <text @click="endRecording" style="font-size: 10px;color: rgb(216, 19, 7);">结束录音</text>
                    </view>

                    <s-icon v-else color="#409EFF" @click="startAudio(item, index, 2)" size="18px" class="icon-class"
                        name="mic"></s-icon>
                </template>


            </view>


        </view>

        <s-toast ref="sToast"></s-toast>

        <!-- <s-button @click="startTest">开始录音</s-button> -->


        <view class="audio-box" v-if="recording">
            <view class="time-box"><span class="start-taste-line">
                    <hr class="hr1" />
                    <hr class="hr2" />
                    <hr class="hr3" />
                    <hr class="hr4" />
                    <hr class="hr5" />
                    <hr class="hr6" />
                    <hr class="hr7" />
                    <hr class="hr8" />
                    <hr class="hr9" />
                    <hr class="hr10" />
                </span></view>
        </view>

        <!-- <view>
            识别结果
        </view>
        <view>
            {{ resultText() }}
        </view> -->
    </view>
</template>

<script>
import { getEmitModel } from "./utils/eventEmit"
import { sha256 } from 'js-sha256';
import config from "./utils/Settings"
import Recorder from "./utils/Recorder.js"

const langArr = ['cn', 'sichuanese', 'cantonese', 'en'];
let interalHandler = null;
let recorder = null;
let ws = null;
let buffers = [];
let stoped = false;
let times = 0;

export default {
    data() {
        return {
            showLoading: false,
            // 录音相关配置
            current: 0,
            recording: false,
            result: [],
            changing: "",
            // 录音相关配置


            // 当前录音下标
            currentIndex: 0,
            currentType: 0,
            currentItem: null
        }
    },
    computed: {
        resultText() {
            return () => {
                if (this.result && Array.isArray(this.result)) {
                    return this.result.join("")
                }
            }
        },
        // 返回当前问答模块数组 
        askList() {
            return () => {
                if (this.models[this.record.model] && (typeof (this.models[this.record.model]) == 'string')) {
                    if (JSON.parse(this.models[this.record.model])) {
                        return JSON.parse(this.models[this.record.model])
                    } else {
                        return []
                    }
                } else {
                    return []
                }
            }
        },
        // 返回当前item内容
        getKeyContent() {
            /**
             * obj 当前问答对象
             * type 1返回问题 2返回回答
             */
            return (obj, type) => {
                if (typeof (obj) === 'object') {
                    const keys = Object.keys(obj)
                    if (keys.length) {
                        return (type === 1) ? obj[keys[0]] : obj[keys[1]]
                    } else {
                        return ""
                    }
                } else {
                    return ""
                }
            }
        }
    },
    methods: {
        addTemplate() {
            if (this.record.options && this.record.options.isOpenClick) {
                const eventData = getEmitModel(
                    "click",
                    this.record.options.eventKey,
                    this.record.model,
                    ""
                );
                this.$emit("event-callback", eventData);
            }
        },
        // 录音结束回填文本
        setText(result) {
            this.handleInput(this.result.join(""), this.currentItem, this.currentType)
            // this.endRecording();
        },
        // 设置当前的录音文本
        setEndRecordText(text) {
            this.handleInput(text, this.currentItem, this.currentType)
            this.recording = false
        },
        // 点击开始录音
        startAudio(item, index, type) {
            console.log("item", item);
            console.log("index", index);
            this.currentIndex = index
            this.currentType = type
            this.currentItem = item

            if (!this.recording) {
                // this.startRecording();
            } else {
                // this.endRecording();
            }
            this.recording = true
            this.$emit("start-recording")
        },
        startTest() {
            if (!this.recording) {
                // setResult([]);
                times = 0;
                this.startRecording();
            } else {
                this.endRecording();
            }
        },
        startRecording() {
            this.recording = true
            buffers = [];
            this.result = []
            this.changing = ""

            this.doRecording();
        },
        endRecording() {
            this.$emit("end-recording")
            // this.stopRecording();
        },
        doRecording() {
            recorder = new Recorder(this.onaudioprocess);
            this.createWS();
            recorder.ready().then(
                () => {
                    recorder.start();
                },
                (error) => {
                    console.log("录音启动失败！ error", error);
                    this.$refs.sToast.show({
                        type: 'error',
                        title: '录音启动失败！',
                        message: error
                    })
                    this.endRecording()
                    if (ws) ws.close();
                },
            );
        },
        createWS() {
            const { appkey, secret, path, count } = config
            // ws仅用于demo，正式使用请使用wss
            const tm = +new Date();
            const sign = sha256(`${appkey}${tm}${secret}`).toUpperCase();
            let sid = null;
            ws = new WebSocket(`${path}?appkey=${appkey}&time=${tm}&sign=${sign}`);
            ws.onopen = () => {
                ws.send(
                    JSON.stringify({
                        type: 'start',
                        sha: '256',
                        data: {
                            lang: langArr[0],
                            appkey: appkey,
                            userId: 'demoUser',
                            udid: 'demoWebDevice',
                        },
                    }),
                );

                // ws.close();
            };
            // let fixed: string[] = [...result];
            ws.onmessage = (evt) => {
                const res = JSON.parse(evt.data);
                if (res.code == 0 && res.text) {
                    console.log("res====>");
                    console.log(res);
                    if (res.type === 'fixed') {
                        // elFixed.current += res.text;
                        this.result.push(res.text);
                        if (this.result.length > count) {
                            this.result.shift();
                        }
                        this.result = [...this.result];
                        this.changing = ""
                        // 回填数据
                        this.setText()
                    } else {
                        this.changing = res.text
                    }
                    sid = res.sid;


                } else {
                    console.log(new Date().valueOf(), '录音结束', res);
                }
            };
            ws.onerror = function (e) {
                recorder.stop();
                console.log(new Date().valueOf(), 'ws error', sid, e);
                ws = null;
            };

            ws.onclose = (e) => {

                console.log(new Date().valueOf(), 'ws close', sid, e);
                // alert('websocket 断开');
                ws = null;
                if (times < 1) {
                    this.createWS();
                    times++;
                } else {
                    if (times > 10) {
                        recorder.stop();
                        return;
                    }
                    setTimeout(this.createWS, 100);
                    times++;
                }
            };
        },
        onaudioprocess(buffer) {
            // console.log(new Date().valueOf(), '-onaudioprocess:', ws?.readyState);

            if (ws && ws.readyState === 1) {
                // console.log('ws send buffer:', buffer.byteLength);
                ws.send(buffer);
            }
        },
        stopRecording() {
            if (!recorder) return;
            recorder.stop();
            if (ws && ws.readyState === 1) {
                ws.send(
                    JSON.stringify({
                        type: 'end',
                    }),
                );
            }
        },

        // 输入内容后回发相关信息
        handleInput(val, item, type) {
            if (item && (typeof (item) === 'object')) {
                const list = this.askList()
                const index = list.findIndex(k => {
                    const keys = Object.keys(k)
                    const itemKeys = Object.keys(item)
                    return type === 1 ? (keys[0] === itemKeys[0]) : (keys[0] === itemKeys[0])
                })
                if (index > -1) {
                    this.$emit("change", {
                        index,
                        value: val,
                        type
                    }, this.record.model)
                }
            }
        },
        /**
         * 删除指定问答项目
         * @param {*} item 
         * @param {*} index 
         */
        deleteItem(item) {
            if (this.models[this.record.model] && (typeof (this.models[this.record.model]) === "string")) {
                let data = JSON.parse(this.models[this.record.model])
                if (Array.isArray(data)) {
                    const index = data.findIndex(k => {
                        return Object.hasOwn(k, Object.keys(item)[0])
                    })
                    if (index > -1) {
                        data.splice(index, 1)
                    }
                    this.$emit("change-models", this.record.model, JSON.stringify(data))
                }
            }
        },
        /**
         * 新增问答项
         */
        addItem() {
            let data = JSON.parse(this.models[this.record.model])

            const index = data.findIndex(k => {
                const keys = Object.keys(k)
                return keys.includes(key)
            })

            // 如果生成的key重复则重新生成
            if (index > -1) {
                this.addItem()
                return
            }

            const sectionObj = {
                // 原本想加一个id作为每一个问答项目的标识，但是里面的换行输入key是唯一的，所以不需要添加了
                // id: new Date().getTime()
            }

            // 生成key后则正常新增template json数据以及 models 数据
            const key = this.uuid2(14, 10)
            const askChildren = []
            const tempOptions = JSON.parse(JSON.stringify(this.record.options))

            for (let i = 0; i < 2; i++) {
                const key = `warpInput_${this.uuid2(14, 10)}`
                askChildren.push({
                    type: "warpInput",
                    label: "换行输入框",
                    key,
                    model: key,
                    options: {
                        leftLabel: "",
                        rightLabel: "",
                        inputLength: 50,
                        fontSize: this.record.options.fontSize,
                        fontFamily: this.record.options.fontFamily
                    }
                })

                sectionObj[key] = i === 0 ? '问：' : '答：'
            }

            // 同步添加options
            tempOptions.children.push({
                key: `askTemplateItem_${this.uuid2(14, 10)}`,
                children: askChildren
            })

            this.$emit("add-options", tempOptions)



            // 同步models数据
            const tempString = this.models[this.record.model]
            if (typeof (tempString) == 'string') {
                const tempData = JSON.parse(tempString)
                tempData.push(sectionObj)

                this.$emit("change-models", this.record.model, JSON.stringify(tempData))
            }


        },
        /**
        * 生成指定长度uuid
        * @param {*} len 长度
        * @param {*} radix 进制
        * @returns 
        */
        uuid2(len, radix) {
            var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
            var uuid = [],
                i;
            radix = radix || chars.length;

            if (len) {
                // Compact form
                for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
            } else {
                // rfc4122, version 4 form
                var r;

                // rfc4122 requires these characters
                uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
                uuid[14] = '4';

                // Fill in random data.  At i==19 set the high bits of clock sequence as
                // per rfc4122, sec. 4.1.5
                for (i = 0; i < 36; i++) {
                    if (!uuid[i]) {
                        r = 0 | Math.random() * 16;
                        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
                    }
                }
            }

            return uuid.join('');
        }
    },
    props: {
        // 问答模块是否显示模板按钮
        showAskTemplate: {
            type: Boolean,
            default: true
        },
        //  是否显示增删改查编辑按钮，以及输入框是否禁用
        showEditBtn: {
            type: Boolean,
            default: true
        },
        value: {
            type: String,
            default: ""
        },
        // 当前选项对应的json数据
        record: {
            type: Object,
            default: () => { }
        },
        // 传入的当前models
        models: {
            type: Object,
            default: () => { }
        },
        // 是否禁用
        disabled: {
            type: Boolean,
            default: false
        },
    },
}
</script>

<style scoped lang="scss">
.ask-template-wrapper {

    .time-box .start-taste-line hr {
        background-color: rgb(41, 121, 255); //声波颜色
        width: 3px;
        height: 6px;
        margin: 0 0.03rem;
        display: inline-block;
        border: none;
    }

    hr {
        animation: note 0.2s ease-in-out;
        animation-iteration-count: infinite;
        animation-direction: alternate;
    }

    .audio-box {
        position: fixed;
        left: 50%;
        bottom: 30px;
        transform: translateX(-50%);
        z-index: 999;
    }

    .hr1 {
        animation-delay: -1s;
    }

    .hr2 {
        animation-delay: -0.9s;
    }

    .hr3 {
        animation-delay: -0.8s;
    }

    .hr4 {
        animation-delay: -0.7s;
    }

    .hr5 {
        animation-delay: -0.6s;
    }

    .hr6 {
        animation-delay: -0.5s;
    }

    .hr7 {
        animation-delay: -0.4s;
    }

    .hr8 {
        animation-delay: -0.3s;
    }

    .hr9 {
        animation-delay: -0.2s;
    }

    .hr10 {
        animation-delay: -0.1s;
    }

    @keyframes note {
        from {
            transform: scaleY(1);
        }

        to {
            transform: scaleY(4);
        }
    }

    .ask-item {
        margin: 10px 0 10px 0;
    }

    width: 100%;

    .title {
        margin-bottom: 10px;
        display: flex;
        justify-content: space-between;
    }

    .title-right {
        display: flex;
        align-items: center;
        padding-right: 10px;
    }

    .question {
        position: relative;
        margin-bottom: 15px;
    }

    .answer {
        position: relative;
    }

    .icon-class {
        position: absolute;
        right: 10px;
        bottom: 10px;
        content: "";
        display: block;
        z-index: 3;
    }
}
</style>