<template>
    <el-row>
        <el-col :span="12">
            <div id="terminal" v-loading="flag.loading" ref="terminal" :element-loading-text="state.lang.connect"
                @click.right.native="showClear($event)"></div>
        </el-col>
        <el-col :span="12">
            <div id="response" v-loading="flag.loading" ref="response" :element-loading-text="state.lang.connect"></div>
        </el-col>
    </el-row>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch, reactive } from "vue";
import { useStore } from "vuex";
import { Terminal } from "xterm";
import "xterm/css/xterm.css";
const { state } = useStore();
const prop = defineProps({
    url: {
        type: String,
        default: null
    },
    msgFilter: {
        type: Function,
        defalut: msg => {
            return { unlock: false, data: msg };
        }
    },
    prmt: {
        type: String,
        default: ">"
    }
});
const flag = reactive({
    loading: true,
    lock: true
});
const terminal = ref(null);
const response = ref(null);

const terminalSocket = ref();
const term = ref();
const rsp = ref();
let text = "";

const runRealTerminal = () => {
    flag.loading = false;
    term.value.write(prop.prmt);
    flag.lock = false;
}

const onWSReceive = (message) => {
    if (prop.msgFilter) {
        const data = prop.msgFilter(message.data);
        if (data) {
            rsp.value.writeln(data)
        } else {
            flag.lock = false
            term.value.write(prop.prmt)
        }
    } else {
        rsp.value.writeln(message.data)
        rsp.value.write(prop.prmt)
        flag.lock = false;
    }
}

const errorRealTerminal = (ex) => {
    let message = ex.message;
    if (!message) message = 'disconnected'
    term.value.write(`\x1b[31m${message}\x1b[m\r\n`)
    console.log("err");
}
const closeRealTerminal = () => {
    console.log("close");
}

const initWS = () => {
    if (!prop.url) {
        return;
    }
    terminalSocket.value = new WebSocket(prop.url);
    terminalSocket.value.onopen = runRealTerminal;
    terminalSocket.value.onmessage = onWSReceive;
    terminalSocket.value.onclose = closeRealTerminal;
    terminalSocket.value.onerror = errorRealTerminal;
}

const onKey = e => {
    if (flag.lock) {
        return;
    }
    //\x1B ESC  
    //\x1BOP-\x1B[24~ F1-F12
    const key = e.key;
    if (key.indexOf("\u001b") !== -1) {
        return;
    }
    if (isWsOpen()) {
        if (key === '\x7F') {
            if (text.length > 0) {
                term.value.write("\b \b");
                text = text.substring(0, text.length - 1)
            }
            return;
        }
        if (key == '\r') {
            term.value.writeln(key)
            if (e.domEvent.ctrlKey) {
                text += key;
            } else {
                sendText(text);
                text = "";
            }
        } else {
            text += key
            term.value.write(key)
        }
    }
}
const initTerm = () => {
    const options = {
        lineHeight: 1.2,
        fontSize: 16,
        fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
        theme: {
            background: '#181d28',
        },
        // 光标闪烁
        cursorBlink: true,
        cursorStyle: 'underline',
        scrollback: 100,
        tabStopWidth: 2,
        cols: 80
    }
    options.cols = Math.ceil((window.innerWidth - 80) / 20)
    term.value = new Terminal(options);
    term.value.open(terminal.value);
    term.value.onKey(onKey);

    options.cursorBlink = false;
    rsp.value = new Terminal(options);
    rsp.value.open(response.value);

}

const sendText = str => {
    if (str) {
        terminalSocket.value.send(str);
        flag.lock = true;
    } else {
        term.value.write(prop.prmt);
    }
}

// 是否连接中0 1 2 3 
const isWsOpen = () => {
    const readyState = terminalSocket.value && terminalSocket.value.readyState;
    return readyState === 1
}

const showClear = e => {
    // 去掉默认事件
    document.oncontextmenu = function (e) {
        e.preventDefault();
    };
    navigator.clipboard.readText().then(content => {
        term.value.write(content)
        text += content;
        // sendText(content);
    })
    // term.value.clear();
}

//监听类型变化，重置term
watch(() => prop.url, () => {
    term.value.reset();
    rsp.value.reset();
    flag.loading = true;
    flag.lock = false;
    terminalSocket.value && terminalSocket.value.close();
    terminalSocket.value = null;
    initWS();
    // 重置
})

onMounted(() => {
    initWS();
    initTerm();
})
onBeforeUnmount(() => {
    terminalSocket.value && terminalSocket.value.close();
    term.value.dispose();
})
</script>
<style lang="scss" scoped>
#terminal {
    width: 100%;
    height: 100%;
}
</style>