<template>
  <div>
    <el-card style="margin-bottom: 10px" class="cardTop">
      <el-form :inline="true" label-width="auto" ref="dialogFormRef" class="form-four">
        <el-form-item label="检测源" prop="sourceId">
          <el-select
            v-model="controlContent.sourceId"
            collapse-tags
            placeholder="请选择检测源"
            :disabled="!isSourceSwitchEnabled"
          >
            <el-option
              v-for="(option, index) in pqSourceArray"
              :key="index"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>

        <el-form-item label="检测脚本" prop="scriptId">
          <el-select
            v-model="controlContent.scriptId"
            collapse-tags
            placeholder="请选择检测脚本"
            @change="handleScriptChange"
          >
            <el-option
              v-for="(option, index) in scriptArray"
              :key="index"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>

        <el-form-item>
          <el-button
            type="primary"
            :icon="Connection"
            @click="start"
            :disabled="!isConnectButtonEnabled"
          >
            源通讯
          </el-button>
          <el-button type="text" :style="{ color: connectionStatusColor }" disabled>
            <span v-if="connectionState.status === 'connecting'" class="connection-loading-spinner"></span>
            {{ connectionStatusText }}
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card v-if="show" style="margin-bottom: 10px">
      <div class="connection-status-row">
        <div class="connection-status-left">
          <span class="connection-status-dot" :class="`is-${connectionState.status}`"></span>
          <span class="connection-status-text">{{ connectionStatusText }}</span>
        </div>
        <el-divider direction="vertical" />
        <div class="running-script-status" :title="runningScriptStatusText">{{ runningScriptStatusText }}</div>
      </div>
    </el-card>

    <el-card v-if="show">
      <ControlSourceDetail
        v-if="secondLevelOptions.length > 0"
        ref="controlSourceDetailRef"
        :options="secondLevelOptions"
        :formContent="formContent"
        :formControl="controlContent"
        @update:activeName="handleActiveNameChange"
        @update:active-index="handleActiveIndexChange"
        v-model:startDisabeld="startDisabeld"
        @update:startDisabeld="startDisabeld = $event"
        v-model:pauseDisabled="pauseDisabled"
        @update:pauseDisabled="pauseDisabled = $event"
        @update:runningScriptName="runningScriptName = $event"
      />
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, reactive, ref, watch } from "vue";
import { useDictStore } from "@/stores/modules/dict";
import ControlSourceDetail from "@/views/machine/controlSource/components/controlSourceDetail.vue";
import { type TestScript } from "@/api/device/interface/testScript";
import type { Dict } from "@/api/system/dictionary/interface";
import { getDictTreeByCode } from "@/api/system/dictionary/dictTree";
import { Connection } from "@element-plus/icons-vue";
import { getPqScriptList, getTestSourceList } from "@/api/plan/plan.ts";
import { TestSource } from "@/api/device/interface/testSource";
import { CascaderOption, ElMessage } from "element-plus";
import { useRouter } from "vue-router";
import { useModeStore } from "@/stores/modules/mode";
import socketClient from "@/utils/webSocketClient";
import { checkSimulate } from "@/api/device/controlSource/index.ts";
import { controlSource } from "@/api/device/interface/controlSource";
import { JwtUtil } from "@/utils/jwtUtil";
import mittBus, { TAB_CLOSED_EVENT } from "@/utils/mittBus";
import {
  applyConnectionTerminalMessage,
  createDisconnectedState,
  getConnectionStatusText,
  isConnectButtonEnabled as canConnect,
  isSourceSelectable,
  resolveConnectionFailureReason,
  shouldHandleConnectionTerminalMessage,
} from "./connectionState";

const show = ref(false);
const router = useRouter();
const modeId = ref();
const controlSourcePath = "/machine/controlSource";
const secondLevelOptions: any[] = [];
const dialogFormRef = ref();
const dictStore = useDictStore();
const pqSourceList = ref<TestSource.ResTestSource[]>([]);
const modeStore = useModeStore();
const pqSourceArray = ref<{ label: string; value: string }[]>([]);
const scriptArray = reactive<{ label: string; value: string }[]>([]);
const formContent = ref<TestScript.ResTestScript>({
  id: "",
  name: "",
  type: "",
  valueType: "",
  pattern: modeId.value,
  standardName: "",
  standardTime: "",
  state: 1,
});
const connectionState = ref(createDisconnectedState());
const startDisabeld = ref(true);
const pauseDisabled = ref(true);
const runningScriptName = ref("");
const controlSourceDetailRef = ref<InstanceType<typeof ControlSourceDetail>>();

const controlContent = ref<controlSource.ResControl>({
  userPageId: "",
  scriptId: "",
  scriptIndex: 0,
  sourceId: "",
});

const dataSocket = reactive({
  socketServe: socketClient.Instance,
});
const webMsgSend = ref<any>();

const handleSocketMessage = (res: { code?: number; message?: string }) => {
  if (res.code === 20000) {
    ElMessage.error(res.message || "请求失败");
    return;
  }
  webMsgSend.value = res;
};

const bindSocket = () => {
  const socket = socketClient.Instance;
  dataSocket.socketServe = socket;
  socket.connect();
  socket.registerCallBack("aaa", handleSocketMessage);
};

const unbindSocket = () => {
  dataSocket.socketServe?.unRegisterCallBack?.("aaa");
};

const closeSocket = () => {
  unbindSocket();
  if (dataSocket.socketServe?.connected) {
    dataSocket.socketServe.closeWs();
  }
};

const isSourceSwitchEnabled = computed(() => isSourceSelectable(connectionState.value));
const isConnectButtonEnabled = computed(() => canConnect(connectionState.value));
const connectionStatusText = computed(() => getConnectionStatusText(connectionState.value));
const runningScriptStatusText = computed(() =>
  runningScriptName.value ? `当前正在加量的脚本：${runningScriptName.value}` : "当前无正在加量脚本"
);
const connectionStatusColor = computed(() => {
  switch (connectionState.value.status) {
    case "connecting":
      return "#e6a23c";
    case "connected":
      return "#67c23a";
    case "failed":
      return "#f56c6c";
    case "disconnected":
    default:
      return "#303133";
  }
});

const resetConnectionState = () => {
  connectionState.value = createDisconnectedState();
};

const markConnectionFailed = (message: {
  data?: unknown;
  desc?: string;
  requestId?: string;
  operateCode?: string;
}) => {
  connectionState.value = {
    status: "failed",
    reason: resolveConnectionFailureReason(message),
  };
};

onMounted(async () => {
  if (!socketClient.Instance) {
    console.error("WebSocket 客户端实例不存在");
    return;
  }

  bindSocket();

  const pqSourceResult = await getTestSourceList({
    pattern: dictStore.getDictData("Pattern").find(item => item.name === modeStore.currentMode)?.id,
    datasourceIds: "",
    sourceIds: "",
    planId: "",
    scriptName: "",
    errorSysName: "",
    sourceName: "",
    devIds: [],
    id: "",
    name: "",
    dataSourceId: "",
    scriptId: "",
    errorSysId: "",
    timeCheck: 0,
    testState: 0,
    reportState: 0,
    result: 0,
    code: 0,
    state: 1,
  });

  pqSourceList.value = pqSourceResult.data as TestSource.ResTestSource[];
  const sourceArray = Array.isArray(pqSourceList.value) ? pqSourceList.value : [];
  pqSourceArray.value = sourceArray.map(item => ({
    label: item.name || "",
    value: item.id,
  }));

  if (pqSourceArray.value.length > 0) {
    controlContent.value.sourceId = pqSourceArray.value[0].value;
  }

  const patternId = dictStore.getDictData("Pattern").find(item => item.name === modeStore.currentMode)?.id;
  const { data } = await getPqScriptList({ pattern: patternId });
  scriptArray.push(...data.map(item => ({ label: item.name, value: item.id })));
  if (scriptArray.length > 0) {
    controlContent.value.scriptId = scriptArray[0].value;
  }

  nextTick(async () => {
    await treeInfo(modeStore.currentMode);
    formContent.value.pattern = modeId.value;
    formContent.value.id = controlContent.value.scriptId;
    show.value = true;
  });
});

onActivated(() => {
  bindSocket();
});

onDeactivated(() => {
  unbindSocket();
});

onBeforeUnmount(() => {
  unbindSocket();
  mittBus.off(TAB_CLOSED_EVENT, handleTabClosed);
});

const handleTabClosed = (closedPath: string) => {
  if (closedPath !== controlSourcePath) {
    return;
  }
  closeSocket();
};

mittBus.on(TAB_CLOSED_EVENT, handleTabClosed);

watch(webMsgSend, newValue => {
  if (!newValue) {
    return;
  }

  if (newValue.requestId?.includes("formal_real&&") && newValue.operateCode === "OPER_GATHER") {
    if (newValue.code === 10200) {
      ElMessage.success("启动成功!");
      startDisabeld.value = false;
      pauseDisabled.value = false;
      controlSourceDetailRef.value?.startTimeCount();
    } else if (newValue.code !== 10201) {
      ElMessage.error("启动失败!");
      startDisabeld.value = false;
      pauseDisabled.value = true;
    }
  }

  if (newValue.requestId?.includes("close_source") && newValue.operateCode === "CLOSE_GATHER") {
    if (connectionState.value.status !== "connected" || newValue.code !== 10200) {
      return;
    }

    setTimeout(() => {
      ElMessage.success("停止成功!");
      resetConnectionState();
      startDisabeld.value = true;
      pauseDisabled.value = true;
      controlSourceDetailRef.value?.stopTimeCount();
    }, 5000);
  }

  if (!shouldHandleConnectionTerminalMessage(newValue)) {
    return;
  }

  switch (newValue.requestId) {
    case "yjc_ytxjy":
      if (newValue.operateCode === "INIT_GATHER") {
        connectionState.value = applyConnectionTerminalMessage(connectionState.value, newValue);
        if (newValue.code === 10200) {
          ElMessage.success("源连接成功!");
          startDisabeld.value = false;
          pauseDisabled.value = false;
        } else {
          ElMessage.error(connectionStatusText.value);
          startDisabeld.value = true;
          pauseDisabled.value = true;
        }
      }
      break;
    case "connect":
      if (newValue.operateCode === "Source") {
        markConnectionFailed(newValue);
        ElMessage.error(resolveConnectionFailureReason(newValue));
        startDisabeld.value = true;
        pauseDisabled.value = true;
      }
      // else if (newValue.operateCode === "Dev") {
      //   ElMessage.error(resolveConnectionFailureReason(newValue));
      //   startDisabeld.value = true;
      //   pauseDisabled.value = true;
      // }
      break;
    case "server_error":
      if (newValue.operateCode === "server_error") {
        markConnectionFailed(newValue);
        ElMessage.error(connectionStatusText.value);
        startDisabeld.value = true;
        pauseDisabled.value = true;
      }
      break;
  }
});

watch(
  () => controlContent.value.sourceId,
  (newValue, oldValue) => {
    if (!oldValue || newValue === oldValue) {
      return;
    }
    resetConnectionState();
    startDisabeld.value = true;
    pauseDisabled.value = true;
    runningScriptName.value = "";
    controlSourceDetailRef.value?.stopTimeCount();
  }
);

const treeInfo = async (currentMode: string) => {
  const data: Dict.ResDictTree = {
    name: "",
    id: "",
    pid: "",
    pids: "",
    code: "Script_Indicator_Items",
    sort: 0,
  };
  const result = await getDictTreeByCode(data);
  const result1 = (await getDictTreeByCode({ ...data, code: "Script_Error" })).data[0].children;
  const allOptions = convertToOptions(result.data as Dict.ResDictTree[]);
  const setAllTree = await setTree(allOptions[0]?.children || [], result1);
  secondLevelOptions.push(...setAllTree);
  modeId.value = dictStore.getDictData("Pattern").find(item => item.name === currentMode)?.id;
};

const setTree = async (data: any[], data1: any[]) => {
  data.forEach(item => {
    data1.forEach(item1 => {
      if (item.label.replace(/准确度|检测/g, "") === item1.name) {
        item.value = item1.id;
      }
    });
  });
  return data;
};

const convertToOptions = (dictTree: Dict.ResDictTree[]): CascaderOption[] => {
  return dictTree.map(item => ({
    value: item.id,
    code: item.code.split("-")[1] || item.code.split("-")[0],
    label: item.name,
    children: item.children ? convertToOptions(item.children) : undefined,
  }));
};

const scriptId = ref("");
const scriptIndex = ref(0);

const handleActiveNameChange = (newActiveName: string) => {
  scriptId.value = newActiveName;
};

const handleActiveIndexChange = (newActiveIndex: number) => {
  scriptIndex.value = newActiveIndex;
};

const handleScriptChange = () => {
  router.push({
    path: "/machine/controlSource",
    state: { title: "新增检测脚本", row: "", mode: modeStore.currentMode },
  });
};

const start = async () => {
  if (!isConnectButtonEnabled.value) {
    return;
  }

  connectionState.value = {
    status: "connecting",
    reason: "",
  };
  startDisabeld.value = true;
  pauseDisabled.value = true;
  controlContent.value.userPageId = JwtUtil.getLoginName();
  controlContent.value.scriptIndex = scriptIndex.value;

  try {
    await checkSimulate(controlContent.value);
  } catch (error: any) {
    connectionState.value = {
      status: "failed",
      reason: error?.message || "请求失败",
    };
    ElMessage.error(connectionStatusText.value);
  }
};
</script>

<style lang="scss" scoped>
:deep(.cardTop) {
  .el-card__body {
    padding: 20px 0 0 20px;
  }
}

.form-four {
  display: flex;
  flex-wrap: wrap;

  .el-form-item {
    display: flex;
    width: 24%;

    .el-form-item__content {
      flex: 1;

      .el-select,
      .el-cascader,
      .el-input__inner,
      .el-date-editor {
        width: 100%;
      }
    }
  }
}

.connection-status-row {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--el-text-color-regular);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
}

.connection-status-left {
  flex: 0 0 10%;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  overflow: hidden;
}

.connection-status-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.running-script-status {
  flex: 0 0 80%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.connection-status-dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #909399;
}

.connection-status-dot.is-connecting {
  background: #e6a23c;
}

.connection-status-dot.is-connected {
  background: #67c23a;
}

.connection-status-dot.is-failed {
  background: #f56c6c;
}

.connection-loading-spinner {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  border: 2px solid rgba(230, 162, 60, 0.25);
  border-top-color: #e6a23c;
  border-radius: 50%;
  vertical-align: -1px;
  animation: control-source-spin 0.8s linear infinite;
}

@keyframes control-source-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
</style>
