<script setup lang="ts">
import { computed, reactive } from "vue";
import { ElIcon, ElRadioButton, ElRadioGroup, useFormItem } from "element-plus";
import { ArrowDown, ArrowUp, Delete, EditPen } from "@element-plus/icons-vue";
import { Typeof } from "@ease-forge/shared";

defineOptions({
    name: 'InOutCenterEditor',
});

// 组件事件定义
const emit = defineEmits<{
    /** 更新内联表格数据 */
    "update:modelValue": [value: ItemJson["dt"]];
}>();

// 定义 Props 类型
interface InOutCenterEditorProps {
    modelValue: ItemJson["dt"];
}

// 读取组件 props 属性
const props = withDefaults(defineProps<InOutCenterEditorProps>(), {});

// 定义 State 类型
interface InOutCenterEditorState {
    portsType: "center" | "in" | "out";
    selectCenterIdx?: number;
    selectInIdx?: number;
    selectOutIdx?: number;
}

// state 属性
const state = reactive<InOutCenterEditorState>({
    portsType: "in",
});

// 定义 Data 类型
interface InOutCenterEditorData {
}

// 内部数据
const data: InOutCenterEditorData = {};
const { formItem } = useFormItem();
const list = computed<Array<string>>(() => {
    const portsType = state.portsType;
    if (portsType === "center") return props.modelValue?.center ?? [];
    if (portsType === "in") return props.modelValue?.in ?? [];
    if (portsType === "out") return props.modelValue?.out ?? [];
    return [];
});
const selectIdx = computed<number | undefined>({
    set: newValue => {
        const portsType = state.portsType;
        if (portsType === "center") state.selectCenterIdx = newValue;
        if (portsType === "in") state.selectInIdx = newValue;
        if (portsType === "out") state.selectOutIdx = newValue;
    },
    get: oldValue => {
        const portsType = state.portsType;
        if (portsType === "center") return state.selectCenterIdx;
        if (portsType === "in") return state.selectInIdx;
        if (portsType === "out") return state.selectOutIdx;
    },
});
const canUpItem = computed(() => selectIdx.value > 0);
const canDownItem = computed(() => selectIdx.value < (list.value.length - 1));
const canDeleteItem = computed(() => selectIdx.value < list.value.length);

function setSelectIdx(idx?: number) {
    selectIdx.value = idx;
}

function addItem() {
    const [list, modelValue] = getListAndModelValue();
    list.push(`D_${Date.now()}`);
    emit("update:modelValue", modelValue);
}

function upItem() {
    if (!canUpItem.value) return;
    const idx = selectIdx.value;
    if (Typeof.noValue(idx)) return;
    if (idx <= 0) return;
    const [list, modelValue] = getListAndModelValue();
    const idxUp = idx - 1;
    const tmp = list[idxUp];
    list[idxUp] = list[idx];
    list[idx] = tmp;
    emit("update:modelValue", modelValue);
    selectIdx.value--;
}

function downItem() {
    if (!canDownItem.value) return;
    const idx = selectIdx.value;
    if (Typeof.noValue(idx)) return;
    const [list, modelValue] = getListAndModelValue();
    if (idx >= (list.length - 1)) return;
    const idxDown = idx + 1;
    const tmp = list[idxDown];
    list[idxDown] = list[idx];
    list[idx] = tmp;
    emit("update:modelValue", modelValue);
    selectIdx.value++;
}

function deleteItem() {
    if (!canDeleteItem.value) return;
    if (Typeof.noValue(selectIdx.value)) return;
    const [list, modelValue] = getListAndModelValue();
    list.splice(selectIdx.value, 1);
    emit("update:modelValue", modelValue);
    if (selectIdx.value >= list.length) {
        setSelectIdx(undefined);
    }
}

function getListAndModelValue() {
    const modelValue = props.modelValue ?? {};
    const portsType = state.portsType;
    let list: Array<string> = [];
    if (portsType === "center") {
        if (!modelValue.center) modelValue.center = [];
        list = modelValue.center;
    } else if (portsType === "in") {
        if (!modelValue.in) modelValue.in = [];
        list = modelValue.in;
    } else if (portsType === "out") {
        if (!modelValue.out) modelValue.out = [];
        list = modelValue.out;
    }
    return [list, modelValue];
}

interface InOutCenterEditorExpose {
    state: InOutCenterEditorState;
    data: InOutCenterEditorData;
}

const expose: InOutCenterEditorExpose = {
    state,
    data,
};
// 定义组件公开内容
defineExpose(expose);

export type {
    InOutCenterEditorProps,
    InOutCenterEditorState,
}
</script>

<template>
    <div class="flex-column-container in-out-center-editor">
        <ElRadioGroup class="flex-item-fixed flex-justify-content-center" v-model="state.portsType" size="small">
            <ElRadioButton label="Input" value="in"/>
            <ElRadioButton label="Central" value="center"/>
            <ElRadioButton label="Output" value="out"/>
        </ElRadioGroup>
        <div class="flex-item-fill flex-row-container in-out-center-editor-data">
            <div class="flex-item-fixed in-out-center-editor-tools">
                <div class="tools-button-container">
                    <ElIcon class="tools-button-icon" @click="addItem">
                        <EditPen/>
                    </ElIcon>
                    <ElIcon :class="['tools-button-icon', { 'tools-button-disabled': !canUpItem }]" @click="upItem">
                        <ArrowUp/>
                    </ElIcon>
                    <ElIcon :class="['tools-button-icon', { 'tools-button-disabled': !canDownItem }]" @click="downItem">
                        <ArrowDown/>
                    </ElIcon>
                    <ElIcon :class="['tools-button-icon', { 'tools-button-disabled': !canDeleteItem }]" @click="deleteItem">
                        <Delete/>
                    </ElIcon>
                </div>
            </div>
            <div class="flex-item-fill in-out-center-editor-data-list">
                <div
                    v-for="(item, idx) in list"
                    :class="[
                        'list-item',
                        {
                            'list-item-select': selectIdx === idx,
                        },
                    ]"
                    @click="setSelectIdx(idx)"
                >
                    {{ item }}
                </div>
            </div>
        </div>
    </div>
</template>

<style scoped>
.in-out-center-editor {
    width: 100%;
    height: 160px;
}

.in-out-center-editor-data {
    margin-top: 6px;
    border: 1px solid #dddddd;
}

.in-out-center-editor-tools {
    background-color: #f5f5f5;
    border-right: 1px solid #dddddd;
    width: 28px;
    padding: 4px 0;
}

.tools-button-container {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: center;
    gap: 4px;
    cursor: pointer;
    height: 100%;
}

.tools-button-container > .tools-button-icon {
    color: #8c8c8c;
    padding: 4px;
    font-size: 22px;
    border-radius: 2px;
}

.tools-button-container > .tools-button-icon:hover {
    color: #595959;
    background-color: #d9d9d9;
}

.tools-button-container > .tools-button-icon:active {
    color: #434343;
    background-color: #bfbfbf;
}

.tools-button-container > .tools-button-disabled {
    cursor: not-allowed;
}

.tools-button-container > .tools-button-disabled.tools-button-icon,
.tools-button-container > .tools-button-disabled.tools-button-icon:hover,
.tools-button-container > .tools-button-disabled.tools-button-icon:active {
    color: #d9d9d9;
    background-color: unset;
    pointer-events: none;
}

.in-out-center-editor-data-list {
    overflow-y: auto;
}

.list-item {
    padding: 0 2px;
    cursor: pointer;
    border-bottom: 1px solid #f0f0f0;
    user-select: none;
    color: #262626;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.list-item:hover {
    background-color: #f0f0f0;
}

.list-item:active {
    background-color: #dddddd;
}

.list-item.list-item-select,
.list-item.list-item-select:hover,
.list-item.list-item-select:active {
    background-color: #d9d9d9;
}
</style>
