<template>
  <div class="app-container">
    <el-row :gutter="20">
      <el-col :span="4" class="sidebar-wrapper">
        <el-input
            v-model="modelQueryParams.name"
            placeholder="请输入模型名称"
            clearable
            prefix-icon="Search"
            style="margin-bottom: 10px"
            @change="getModelList()"
        />
        <el-radio-group style="flex-wrap: nowrap;" v-model="modelQueryParams.isPublic" @change="getModelList">
          <el-radio-button label="已发布" value="1"/>
          <el-radio-button label="未发布" value="0"/>
        </el-radio-group>
        <div class="tool-container">
          <div :class="{'active': modelId === item.mdid}" v-for="(item, index) in modelOptions" :key="index"
               class="tool-item" @click="handleModelClick(item.mdid)">
            {{ item.name }}
          </div>
        </div>
      </el-col>
      <!--    v-loading="loading"   -->
      <el-col :span="16" style="position: relative;">
        <el-button-group class="flow-button-group">
          <el-button type="primary" :icon="Promotion" @click="saveStep">保存</el-button>
          <!--          <el-button type="primary" :icon="Check">测试</el-button>-->
        </el-button-group>
        <VueFlow :nodes="nodes" :edges="edges" @drop="onDrop" @dragover="onDragOver" @dragleave="onDragLeave"
                 @connect="onConnect" fit-view-on-init>
          <template #node-special="specialNodeProps">
            <SpecialNode :id="specialNodeProps.id" :position="specialNodeProps.position" :data="specialNodeProps.data"/>
          </template>

          <!-- bind your custom edge type to a component by using slots, slot names are always `edge-<type>` -->
          <template #edge-special="specialEdgeProps">
            <SpecialEdge v-bind="specialEdgeProps"/>
          </template>
        </VueFlow>
      </el-col>
      <el-col :span="4" class="sidebar-wrapper">
        <el-input
            v-model="toolQueryParams.name"
            placeholder="请输入工具名称"
            clearable
            prefix-icon="Search"
            style="margin-bottom: 10px"
            @change="getServiceList()"
        />
        <el-radio-group style="flex-wrap: nowrap;" v-model="toolType">
          <el-radio-button label="工具类" value="1"/>
          <el-radio-button label="服务" value="0"/>
        </el-radio-group>
        <div v-show="toolType === '1'" class="tool-container">
          <div></div>
        </div>
        <div v-show="toolType === '0'" class="tool-container">
          <div v-for="(item, index) in serviceList" :key="index" class="tool-item" :draggable="true"
               @dragstart="onDragStart($event, item)">
            {{ item.label }}
          </div>
        </div>
      </el-col>
    </el-row>

    <!-- 添加或修改部门对话框 -->
    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
      <template #header="{ close, titleId, titleClass }">
        <div style="display: flex;align-items: center;">
          <el-tag>{{ form.type }}</el-tag>
          <h4 style="margin: 0 0 0 5px;" :id="titleId" :class="titleClass">{{ form.label }}</h4>
        </div>
      </template>
      <el-form ref="deptRef" :model="form" :rules="rules" label-width="80px" label-position="top">
        <el-form-item label="API">
          <el-row style="width: 100%;" :gutter="20">
            <el-col :span="4">
              <el-select v-model="form.config.method" style="width: 100px">
                <el-option label="GET" value="GET"></el-option>
                <el-option label="POST" value="POST"></el-option>
                <el-option label="HEAD" value="HEAD"></el-option>
                <el-option label="PATCH" value="PATCH"></el-option>
                <el-option label="PUT" value="PUT"></el-option>
                <el-option label="DELETE" value="DELETE"></el-option>
              </el-select>
            </el-col>
            <el-col :span="20">
              <el-input v-model="form.config.url" placeholder="请输入URL"/>
            </el-col>
          </el-row>
        </el-form-item>
        <el-form-item label="HEADERS">
          <dynamic-map v-model="form.config.headers"></dynamic-map>
        </el-form-item>
        <el-form-item label="PARAMS">
          <dynamic-map v-model="form.config.params"></dynamic-map>
        </el-form-item>
        <el-form-item label="BODY">
          <!-- 单选 -->
          <el-radio-group v-model="form.bodyType">
            <el-radio value="none">none</el-radio>
            <el-radio value="form-data">form-data</el-radio>
            <el-radio value="x-www-form-urlencoded">x-www-form-urlencoded</el-radio>
            <el-radio value="JSON">JSON</el-radio>
            <el-radio value="raw">raw</el-radio>
          </el-radio-group>
          <dynamic-map v-if="form.bodyType === 'x-www-form-urlencoded'" v-model="form.config.body"></dynamic-map>
        </el-form-item>
        <el-row>
          <el-col :span="12">
            <el-form-item label="失败处理">
              <el-select v-model="form.errorPolicy" style="width: 100px">
                <el-option label="报错" value="ABORT"></el-option>
                <el-option label="忽视" value="IGNORE"></el-option>
                <el-option label="重连" value="RETRY"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.errorPolicy === 'RETRY'" label="失败重连次数">
              <el-input-number v-model="form.retryCount" :min="1" :max="30"/>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import DynamicMap from '@/components/DynamicMap/index.vue'
import {Promotion} from '@element-plus/icons-vue'
import {ref} from 'vue'
import {useVueFlow, VueFlow} from '@vue-flow/core'
import SpecialNode from './components/SpecialNode.vue'
import SpecialEdge from './components/SpecialEdge.vue'
import {getPtServiceList} from "@/api/service/info.js";
import {getModelList2} from "@/api/register/regCom.js";
import {copyObject} from "@/utils/index.js";
import {getWorkflowByModelId, saveWorkflow} from "@/api/standardization/workflow.js";

const {
  onInit,
  findNode,
  fitView,
  snapToGrid,
  addEdges,
  addNodes,
  toObject,
  screenToFlowCoordinate,
  onNodesInitialized,
  updateNode,
  onNodeClick,
  onEdgeClick,
  getNodes,
  getEdges,
  removeNodes,
  removeEdges,
} = useVueFlow()
// to enable snapping to grid
snapToGrid.value = true

const {proxy} = getCurrentInstance();
const modelQueryParams = ref({
  name: undefined,
  isPublic: '0',
});
const toolQueryParams = ref({
  name: undefined,
});
const modelOptions = ref(undefined);
const modelId = ref(undefined);
const loading = ref(true);
const toolType = ref('0');
const serviceList = ref([]);

const draggedData = ref(undefined);
const isDragging = ref(false);
const isDragOver = ref(false);
const nodes = ref([]);
const edges = ref([]);

const title = ref('')
const open = ref(false)


function handleModelClick(mid) {
  modelId.value = mid
  removeNodes(getNodes.value)
  removeEdges(getEdges.value)
  getWorkflow(mid)
}

onInit((instance) => {
  fitView()
  const node = findNode('1')
  if (node) {
    node.position = {x: 100, y: 100}
  }
})

onNodeClick(({event, node}) => {
  form.value = node.data
  open.value = true
  title.value = node.data.label
  nodeId.value = node.id
});

// Edge click event handler
onEdgeClick(({event, edge}) => {
  console.log('Edge clicked:', edge, event);
});

const data = reactive({
  form: {config: {}},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    userName: undefined,
    phonenumber: undefined,
    status: undefined,
    deptId: undefined
  },
  rules: {
    userName: [{required: true, message: "用户名称不能为空", trigger: "blur"}, {
      min: 2,
      max: 20,
      message: "用户名称长度必须介于 2 和 20 之间",
      trigger: "blur"
    }],
    nickName: [{required: true, message: "用户昵称不能为空", trigger: "blur"}],
    password: [{required: true, message: "用户密码不能为空", trigger: "blur"}, {
      min: 5,
      max: 20,
      message: "用户密码长度必须介于 5 和 20 之间",
      trigger: "blur"
    }, {pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符：< > \" ' \\\ |", trigger: "blur"}],
    email: [{type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"]}],
    phonenumber: [{pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur"}]
  }
});

const {queryParams, form, rules} = toRefs(data);
const nodeId = ref(null)

/**
 * 开始拖拽选项的事件
 * @param event
 * @param data
 */
function onDragStart(event, data) {
  if (event.dataTransfer) {
    event.dataTransfer.setData('application/vueflow', data)
    event.dataTransfer.effectAllowed = 'move'
  }

  draggedData.value = data
  isDragging.value = true

  document.addEventListener('drop', onDragEnd)
}

/**
 * 拖拽到画布vueflow的事件
 * @param event
 */
function onDragOver(event) {
  event.preventDefault()

  if (draggedData.value) {
    isDragOver.value = true

    if (event.dataTransfer) {
      event.dataTransfer.dropEffect = 'move'
    }
  }
}

/**
 * 拖拽放下的事件
 * @param event
 */
function onDrop(event) {
  const position = screenToFlowCoordinate({
    x: event.clientX,
    y: event.clientY,
  })

  const nodeId = Math.random() + "id";

  const data = copyObject(draggedData.value)
  const newNode = {
    id: nodeId,
    type: 'special',
    position,
    data,
  }

  // 更新位置到鼠标中心
  const {off} = onNodesInitialized(() => {
    updateNode(nodeId, (node) => ({
      position: {x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2},
    }))

    off()
  })

  addNodes(newNode)
}

/**
 * 拖拽到画布外面的的事件
 */
function onDragLeave() {
  isDragOver.value = false
}

/**
 * 拖拽结束
 */
function onDragEnd() {
  isDragging.value = false
  isDragOver.value = false
  draggedData.value = null
  document.removeEventListener('drop', onDragEnd)
}

function onConnect(params) {
  console.log('on connect', params)
  addEdges(params)
}

/** 查询模型列表 */
function getModelList() {
  getModelList2(modelQueryParams.value).then(res => {
    loading.value = false;
    modelOptions.value = res.data;
  });
}

/** 通过条件过滤节点  */
const filterNode = (value, data) => {
  if (!value) return true;
  return data.label.indexOf(value) !== -1;
};

/** 节点单击事件 */
function handleNodeClick(data) {
  queryParams.value.modeId = 1 // data.id;
  handleQuery();
}

/** 搜索按钮操作 */
function handleQuery() {
  queryParams.value.pageNum = 1;
  getList();
}

/** 查询流程图 */
function getList() {
  loading.value = true;
  // listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(res => {
  //   loading.value = false;
  //   userList.value = res.rows;
  //   total.value = res.total;
  // });
}

/** 查询服务列表 */
function getServiceList() {
  getPtServiceList(toolQueryParams.value).then(res => {
    serviceList.value = res.data.map(item => {
      return {
        id: item.id,
        label: item.name,
        type: 'API',
        config: {
          url: item.url,
          method: item.rqtype,
          params: item.params,
          headers: item.headers,
          body: item.body,
        },
        errorPolicy: 'ABORT',
        retryCount: 0,
        outputMapping: null,
        data: item,
      }
    })
  })
}

function submitForm() {
  updateNode(nodeId.value, (node) => ({
    data: form.value,
  }))
  cancel()
}

function cancel() {
  form.value = {config: {}};
  open.value = false;
  title.value = ''
}

function saveStep() {

  if (!modelId.value) {
    proxy.$modal.msgError("请选择模型");
    return
  }

  const nodes = getNodes.value.map(res => {
    return {
      id: res.id,
      type: res.type,
      position: res.position,
      data: res.data,
    }
  })
  const edges = getEdges.value.map(res => {
    return {
      source: res.source,
      target: res.target,
    }
  })
  const data = {
    mdid: modelId.value,
    graph: JSON.stringify({
      nodes: nodes,
      edges: edges,
    }),
  }
  saveWorkflow(data).then(res => {
    // 测试
    proxy.$modal.msgError("请输入建表语句");
  })
}

function getWorkflow(modelId) {
  getWorkflowByModelId(modelId).then(res => {
    if (res.data && res.data.graph) {
      const {nodes, edges} = JSON.parse(res.data.graph)
      addNodes(nodes)
      addEdges(edges)
    }
  })
}


getModelList()
getServiceList()
</script>
<style>
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
</style>
<style scoped>
.app-container {
  height: 100%;

  & > div {
    height: 100%;

    & > div {
      height: 100%;
    }
  }

  .sidebar-wrapper {
    padding: 10px 0;
    border-radius: 8px;
    border: 1px solid var(--el-border-color);
  }

  .tool-container {
    overflow: auto;
    height: calc(100% - 74px);

    .tool-item {
      padding: 5px 10px;
      border-radius: 6px;
      cursor: pointer;

      &:hover, &.active {
        background-color: var(--el-color-primary);
        color: #fff;
      }

    }

  }

  .flow-button-group {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 10;
  }

}

:deep(.el-radio-group) {
  display: flex;
  width: 100%;
  text-align: center;
}

:deep(.el-radio-button) {
  flex: 1;
  border: var(--el-border);
}

:deep(.el-radio-button.is-active) {
  background-color: var(--el-color-primary);
}

:deep(.el-radio-button:first-child) {
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
}

:deep(.el-radio-button:last-child) {
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
}

:deep(.el-radio-button__inner) {
  transition: none;
  border: none !important;
}
</style>