<template>
  <div class="app-container connection-edit">
    <el-card>
      <template #header>
        互联信息</template>

      <el-form ref="editForm" :model="upForm" :rules="upRules" label-width="120">
        <el-row>
          <el-col :span="12">
            <el-form-item label="模型名称">
              <el-input disabled v-model="upForm.model_name" placeholder="目标分类模型" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="模型版本">
              <el-input disabled v-model="upForm.model_version" placeholder="v1.0" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="互联名称" prop="connection_name">
              <el-input v-model="upForm.connection_name" placeholder="请输入互联名称" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="互联说明" prop="connection_desc">
              <el-input v-model="upForm.connection_desc" type="textarea" style="width:100%;" :rows="4"
                placeholder="请输入互联说明" />
            </el-form-item>
          </el-col>

        </el-row>
      </el-form>
    </el-card>
    <el-card style="margin-top: 12px;margin-bottom: 80px;" class="flow-card">
      <template #header>算子互联</template>
      <div class="edit-content" style="position: relative;">
        <div class="item" style="position: relative;width:380px;">
          <div class="line-arrow"
            style="position: absolute;left: 100%;margin-left:10px; width: 80px;border-bottom: solid 1px #409eff;top: 250px;">
            <i-ep-arrow-right style="color:#409eff;position: absolute;right: -7px;top: -9px;" />
          </div>
          <div class="div-title" style="display: none;">
            <i-ep-office-building /><span>可用算子</span>
          </div>
          <div class="div-nodes">
            <nodePanel :lf="lf" ref="ndPanel" />
          </div>
        </div>
        <div style="flex-grow: 1;">
          <editFlow ref="edFlow" @initLf="doInitLf" @updateNode="doUpdateNode" @nodeClick="doNodeClick" />
        </div>
        <div class="item flow-info" style="margin-left: 100px;" v-if="selNode.info">
          <div class="div-title">
            <i-ep-document /><span>算子基本信息</span>
          </div>
          <div class="div-info">
            <div class="row">
              <span class="sp-label">算子名称:</span>
              <span class="sp-text">{{ selNode.info.operator_name }}</span>
            </div>
            <div class="row">
              <span class="sp-label">算子版本:</span>
              <span class="sp-text">{{ selNode.info.operator_version }}</span>
            </div>
            <div class="row">
              <span class="sp-label">算子说明:</span>
              <span class="sp-text">{{ selNode.info.operator_desc }}</span>
            </div>
            <div class="row" v-if="selNode.info.parameters && selNode.info.parameters.inputs">
              <span class="sp-label">输入参数:</span>
              <div class="div-param">
                <div v-if="selNode.info.parameters.inputs.length > 1" class="div-navs">
                  <span v-for="(it, idx) in selNode.info.parameters.inputs" @click="doInputSelected(idx)" :key="idx"
                    class="sp-nav" :class="it.selected ? 'active' : ''">{{ it.input_id }}</span>
                </div>
                <span class="sp-text  sp-paramter scroll" @click="doEdit(selNode.info, '输入参数', 'i')">
                  <span v-for="(it, idx) in selNode.info.parameters.inputs " :key="idx" v-show="it.selected"
                    class="param-item">
                    <paramShow :paramInfo="it"></paramShow>
                  </span>
                </span>
              </div>
            </div>
            <div class="row" style="margin-top:4px;" v-if="selNode.info.parameters && selNode.info.parameters.outputs">
              <span class="sp-label">输出参数:</span>
              <div class="div-param">
                <div v-if="selNode.info.parameters.outputs.length > 1" class="div-navs">
                  <span v-for="(it, idx) in selNode.info.parameters.outputs" @click="doOutputSelected(idx)" :key="idx"
                    class="sp-nav" :class="it.selected ? 'active' : ''">{{ it.output_id }}</span>
                </div>
                <span class="sp-text sp-paramter scroll" @click="doEdit(selNode.info, '输出参数', 'o')">
                  <span v-for="(it, idx) in selNode.info.parameters.outputs " :key="idx" v-show="it.selected"
                    class="param-item">
                    <paramShow :paramInfo="it"></paramShow>
                  </span>
                </span>
              </div>
            </div>
            <div class="row" style="margin-top:4px;" v-if="selNode.info.parameters && selNode.info.parameters.process">
              <span class="sp-label">处理参数:</span>
              <span class="sp-text  sp-paramter scroll" @click="doEdit(selNode.info, '处理参数', 'p')"
                v-if="selNode.info.parameters.process">
                <paramShow :paramInfo="selNode.info.parameters.process"></paramShow>
              </span>
            </div>
          </div>
        </div>
      </div>
    </el-card>
    <el-card class="card-footer">
      <el-button type="primary" @click="doSave">保存</el-button>
      <el-button @click="doCancel">取消</el-button>
    </el-card>
    <EditParamDlg ref="editDlg" @success="doEditSuccess" />
  </div>
</template>

<script setup>
import nodePanel from './nodePanel.vue'
import editFlow from './editFlow.vue'
import ConnApi from '@/api/connection'
import ModelApi from '@/api/models'
import EditParamDlg from './editParamDlg.vue'
import paramShow from './paramShow.vue'
const router = useRouter();
const editForm = ref(ElForm)
const route = useRoute()
const upForm = reactive({
  model_id: '',
  model_name: '',
  model_version: '',
  connection_name: '',
  connection_desc: ''
});
const upRules = computed(() => {
  return {
    connection_name: [{ required: true, trigger: "blur", message: "请输入互联名称", },],
    connection_desc: [{ required: true, trigger: "blur", message: "请输入互联说明", },],
  }
});
const editDlg = ref()
const info = reactive({
  connInfo: null,
  nodes: [],
  editObj: null,
  type: '',
})
const selNode = reactive({
  info: null,
  node: null,
})
let lf = ref(null)
let edFlow = ref()
const ndPanel = ref()
const doOutputSelected = idx => {
  selNode.info.parameters.outputs.forEach((it, i) => {
    it.selected = i == idx;
  });
}
const doInputSelected = idx => {
  selNode.info.parameters.inputs.forEach((it, i) => {
    it.selected = i == idx;
  });
}
const doEditSuccess = (obj) => {
  let t = info.editObj.type;
  if (t == 'i') {
    obj.forEach(o => {
      let cobjs = selNode.info.parameters.inputs.filter(d => d.input_id == o.id);
      if (cobjs.length > 0) {
        let cobj = cobjs[0];
        o.attrs.forEach(oo => {
          if (oo.name == "oper_inout_data_type") {
            cobj.oper_inout_data_type = oo.value;
          } else {
            cobj[oo.name].value = oo.value;
          }
        });
      }
    })
  }
  if (t == 'o') {
    obj.forEach(o => {
      let cobjs = selNode.info.parameters.outputs.filter(d => d.output_id == o.id);
      if (cobjs.length > 0) {
        let cobj = cobjs[0];
        o.attrs.forEach(oo => {
          if (oo.name == "oper_inout_data_type") {
            cobj.oper_inout_data_type = oo.value;
          } else {
            cobj[oo.name].value = oo.value;
          }
        });
      }
    })
  }
  if (t == 'p') {
    obj[0].attrs.forEach(o => {
      selNode.info.parameters.process[o.name]["value"] = o.value;
    });
  }
  let tmps = info.nodes.filter(d => d.id == selNode.info.id);
  if (tmps.length == 0) {
    info.nodes.push(selNode.info)
  } else {
    tmps[0].inputs = selNode.info.parameters.inputs;
    tmps[0].outputs = selNode.info.parameters.outputs;
    tmps[0].process = selNode.info.parameters.process;
  }
  edFlow.value.updateNode(selNode.info, selNode.node);
};
const doEdit = (obj, title, t) => {
  info.editObj = {
    obj: obj,
    title: title,
    type: t
  }
  editDlg.value.showDialog({
    type: t,
    obj: t == 'i' ? obj.parameters.inputs : t == 'o' ? obj.parameters.outputs : obj.parameters.process,
    title: title
  });
}
const objToArr = (obj, t) => {
  let arr = [];
  for (let k in obj) {
    arr.push({ key: k, value: obj[k] })
  }
  return arr;
}
const doUpdateNode = (data) => {
  if (ndPanel && ndPanel.value) {
    ndPanel.value.updateNode(data)
  }
}
const doNodeClick = (node) => {
  if (node) {
    selNode.info = node.data.properties.data;
    selNode.node = node;
    let tmps = info.nodes.filter(d => d.id == selNode.info.id);
    if (tmps.length == 0) {
      info.nodes.push(selNode.info);
    } else {
      selNode.info.parameters.inputs = tmps[0].parameters.inputs;
      selNode.info.parameters.outputs = tmps[0].parameters.outputs;
      selNode.info.parameters.process = tmps[0].parameters.process;
    }

    selNode.info.parameters.inputs.forEach(d => {
      d.selected = false;
    });
    selNode.info.parameters.outputs.forEach(d => {
      d.selected = false;
    });
    if (selNode.info.parameters.inputs.length > 0) {
      selNode.info.parameters.inputs[0].selected = true;
    }
    if (selNode.info.parameters.outputs.length > 0) {
      selNode.info.parameters.outputs[0].selected = true;
    }

  }
  else {
    selNode.info = null;
  }
}
const doInitLf = (o) => {
  lf.value = o.value
}
const doSave = () => {
  let flowData = lf.value.getGraphData();
  if (flowData.nodes.length < 3) {
    ElMessage.error("请绘制算子互联流程图!");
    return;
  }
  let isNoConnect = false;
  let nodeObj = {};
  let operator_list = [];
  flowData.nodes.forEach(n => {
    nodeObj[n.id] = n.properties.data;
    let node = info.nodes.filter(nd => nd.id == n.properties.data.id);
    let oper = {
      operator_id: n.properties.data.id,
      parameters: {}
    }
    if (node.length > 0) {
      oper.parameters.inputs = node[0].inputs;
      oper.parameters.outputs = node[0].outputs;
      oper.parameters.process = node[0].process;
    }
    operator_list.push(oper);
    let tmps = flowData.edges.filter(e => e.sourceNodeId == n.id || e.targetNodeId == n.id);
    if (tmps.length == 0) {
      isNoConnect = true;
    }
  });

  if (isNoConnect) {
    ElMessage.error("请在流程图中连接各个算子!");
    return;
  }
  let operator_connection_list = [];
  flowData.edges.forEach(e => {
    operator_connection_list.push({
      start_oper_id: nodeObj[e.sourceNodeId].id,
      end_oper_id: nodeObj[e.targetNodeId].id,
    });
  });
  operator_list = flowData.nodes.map(it => it.properties.data);
  operator_connection_list = flowData.edges.map(it => {
    let obj = {
      start_oper_id: nodeObj[it.sourceNodeId].id,
      end_oper_id: nodeObj[it.targetNodeId].id,
      start_oper_output_id: it.properties.sourceAnchorId,
      end_oper_input_id: it.properties.targetAnchorId,
    };
    return obj;
  })
  editForm.value?.validate(valid => {
    if (valid) {
      let postData = {
        model_id: upForm.model_id,
        connection_name: upForm.connection_name,
        connection_label: upForm.connection_label,
        connection_desc: upForm.connection_desc,
        operator_list: operator_list,
        operator_connection_list: operator_connection_list,
        operator_node_data: {
          nodes: flowData.nodes,
          edges: flowData.edges
        }
      };
      if (info.type == "add") {
        ConnApi.add(postData).then(d => {
          if (d.data.code == 0) {
            ElMessage.success("增加互联成功!");
            router.push({ path: "/connection/index" })
          }
        });
      } else {
        let id = route.query.id;
        ConnApi.updatAll(id, postData).then(d => {
          if (d.data.code == 0) {
            ElMessage.success("修改互联成功!");
            router.push({ path: "/connection/index" })
          }
        });
      }
    }
  });

}
const doCancel = () => {
  router.push({ path: "/connection/index" })
}
const initConnData = () => {
  let id = route.query.id;
  ConnApi.detail(id).then(d => {
    info.connInfo = d.data?.data || {};
    upForm.model_id = info.connInfo.model_id;
    upForm.model_name = info.connInfo.model_name;
    upForm.model_version = info.connInfo.model_version;
    upForm.model_name = info.connInfo.model_name;
    upForm.connection_name = info.connInfo.connection_name;
    upForm.connection_label = "";
    upForm.connection_desc = info.connInfo.connection_desc;
  });
};
const initEditData = () => {
  let id = route.query.id;
  ConnApi.detail(id).then(d => {
    info.connInfo = d.data?.data || {};
    upForm.model_id = info.connInfo.model_id;
    upForm.model_name = info.connInfo.model_name;
    upForm.model_version = info.connInfo.model_version;
    upForm.connection_name = info.connInfo.connection_name;
    upForm.connection_label = "";
    upForm.connection_desc = info.connInfo.connection_desc;
    edFlow.value.showFlow(info.connInfo)
  });
}
const initData = () => {
  let id = route.query.id;
  ModelApi.findOne(id).then(d => {
    upForm.model_id = d.data.data.model_id;
    upForm.model_name = d.data.data.model_name;
    upForm.model_version = d.data.data.model_version;
  });
}

onMounted(() => {
  if (route.query.type == "edit") {
    info.type = "edit"
    initEditData();
  } else if (route.query.type == "addByConn") {
    info.type = "add"
    initConnData();
  } else {
    info.type = "add"
    initData();
  }
});
</script>
<style scoped lang='scss'>
.connection-edit {
  :deep(.el-card__header) {
    padding: 8px 12px;
    display: flex;
    align-items: center;
    font-weight: bold;
  }

  :deep(.anchors-end) {
    fill: red;
  }

  :deep(.anchors-start) {
    fill: green;
  }

  .sp-paramter {
    height: 100px;
    border: solid 1px #409EFF;
    overflow-y: auto;
    padding: 4px;
    cursor: pointer;

    .param-item {
      display: block;
    }
  }
}

.card-footer {
  position: fixed;
  width: calc(100% - 215px);
  bottom: 0px;

  :deep(.el-card__body) {
    padding: 10px;

    .el-pagination {
      justify-content: end;
    }
  }
}

.flow-card {
  :deep(.el-card__body) {
    padding: 0px;
  }
}

.edit-content {
  display: flex;

  .item {
    width: 300px;

    &.flow-info {
      position: absolute;
      top: 10px;
      right: 10px;
      background: #fff;

      .div-info {
        min-height: unset;
        height: auto;
      }
    }

    .div-title {
      color: #409EFF;
      display: flex;
      align-items: center;
      font-size: 12px;
    }

    .div-nodes {
      border: solid 1px #409EFF;
      min-height: 600px;
      height: 600px;

      :deep(.el-tabs--border-card) {
        border: none;
      }
    }

    .div-chart {
      border: solid 1px #409EFF;
      min-height: 600px;
      height: 600px;
    }

    .div-info {
      border: dotted 1px #409EFF;
      min-height: 600px;
      height: 600px;
      padding: 10px;
      font-size: 12px;

      .row {
        display: flex;

        .sp-label {
          color: #888;
          display: block;
          white-space: nowrap;
        }

        .sp-text {
          flex-grow: 1;
          display: block;
          margin-left: 4px;
        }

        .div-param {
          .div-navs {
            .sp-nav {
              display: inline-block;
              line-height: 24px;
              padding: 0px 12px;
              cursor: pointer;

              &.active {
                background-color: #409EFF;
                color: #fff;
              }
            }
          }
        }
      }
    }
  }
}
</style>