<template>
  <div>
    <MenuTitle title="爬虫管理" subtitle="Spider Manager" />
    <div class="table-content">
      <el-table
        :data="tableData"
        style="width: 100%"
        border
        :header-cell-style="{ textAlign: 'center' }"
        :cell-style="{ textAlign: 'center' }"
        :row-style="{ height: '60px' }"
        v-loading="tableData.length == 0"
        element-loading-background="rgba(48, 65, 86, 0.3)"
      >
        <el-table-column property="number" label="序号" type="index" width="80" />
        <el-table-column property="spider" label="爬虫代号" show-overflow-tooltip />
        <el-table-column property="spider_name" label="爬虫名称" show-overflow-tooltip />
        <el-table-column min-width="200" property="spider_info" label="任务描述" show-overflow-tooltip />
        <el-table-column label="操作">
          <template #default="scope">
            <div class="btn-group">
              <el-button link type="primary" plain @click="handleDetails(scope.row)">查看任务</el-button>
              <el-button link type="primary" plain @click="handleEditSateId" v-if="scope.row.editable">编辑</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
        <Pagination
          :total="pageObj.total"
          v-model:page="pageObj.pageNo"
          v-model:limit="pageObj.pageSize"
          @pagination="getData"
        />
      </div>
    </div>

    <el-dialog style="z-index: 999999" draggable v-model="editDialogVisible" title="指定下载以下卫星" width="550">
      <div class="No-Content" ref="noContentRef">
        <TransitionGroup
          enter-active-class="animate__animated animate__slideInRight"
          leave-active-class="animate__animated animate__slideOutRight"
          enter-from-class="animate__opacity-0"
          leave-to-class="animate__opacity-0"
        >
          <NoItem
            v-for="(no, index) in sateNoList"
            :key="index"
            class="no-item-row"
            :-no="no.norad_cat_id"
            @add-no="handleSateAdd"
            @del-no="handleSateDel"
            :reset-selected="resetSelected"
          ></NoItem>
        </TransitionGroup>
      </div>
      <div class="footer">
        <div class="No">
          <span style="color: white; font-weight: 500">NORAD编号：</span>
          <el-input
            @input="handleNumInput"
            maxlength="6"
            placeholder="请输入编号"
            v-model="curSateNo"
            style="width: 100px"
          ></el-input>
        </div>
        <div class="btns">
          <el-button :disabled="curSateNo == ''" plain type="primary" @click="addNoToList">添加</el-button>
          <el-popconfirm title="确定删除选中编号吗？" width="200" style="background-color: pink">
            <template #reference>
              <el-button :disabled="curSelSateNo.length === 0" plain type="danger">删除</el-button>
            </template>
            <template #actions="{ confirm, cancel }">
              <el-button size="small" @click="cancel">取消</el-button>
              <el-button
                type="danger"
                size="small"
                @click="
                  (e:MouseEvent) => {
                    confirm(e);
                    delNoList();
                  }
                "
              >
                确定
              </el-button>
            </template>
          </el-popconfirm>
          <el-upload
            :on-change="handleFileChange"
            accept=".txt"
            action="#"
            :auto-upload="false"
            :show-file-list="false"
            :before-upload="beforeUpload"
          >
            <el-button type="primary">导入编号文件</el-button>
          </el-upload>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, watch } from "vue";
import Pagination from "@/components/pagination/index.vue";
import { useRouter } from "vue-router";
import { getSpiderList, addSateNo, getSateIdList, deleteSateNoList, addSateNoList } from "@/api/system.ts";
import NoItem from "./components/NoItem.vue";
import { ElMessage, type UploadProps, type UploadRawFile } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";

const router = useRouter();
const tableData = ref([]);
const pageObj = ref({
  total: 10,
  pageSize: 10,
  pageNo: 1,
});
const handleDetails = (row: any) => {
  router.push({
    path: "/osTaskInformation/list",
    query: {
      jump: "yes",
      spiderType: row.spider,
      page: "spiderManager",
    },
  });
};
// 获取爬虫数据的方法
const getData = async () => {
  const res = await getSpiderList({ scrapydServerId: "1", project: "spiders" });
  tableData.value = res.data;
};

const editDialogVisible = ref(false);

//编号item类型定义
interface noradItem {
  id: number;
  norad_cat_id: string;
  create_time: string;
}

const sateNoList = ref<noradItem[]>([]);

const curSateNo = ref("");

const curSelSateNo = ref<string[]>([]);

const resetSelected = ref(false);

//添加选中项到当前列表
const handleSateAdd = (no: string) => {
  if (checkNoLeSix(no)) {
    curSelSateNo.value.push(no);
  }
};

//从当前列表删除选中项
const handleSateDel = (no: string | number) => {
  curSelSateNo.value = curSelSateNo.value.filter((item) => item != no);
};

//添加编号发到后端
const addNoToList = async () => {
  const res = await addSateNo({ norad_id: curSateNo.value });
  if (res.code === 0) {
    ElMessage.success("添加编号成功");
    getSateNoList();
  }
  curSateNo.value = "";
};

//编号文件导入后发送到后端
const fileImptAddNoList = async () => {
  try {
    console.log(textFileNumbers.value);
    const res = await addSateNoList({ norad_id: textFileNumbers.value });
    console.log(res);
    if (res.code === 0) {
      ElMessage.success("导入编号成功");
    }
    getSateNoList();
  } catch (error: any) {
    ElMessage.error(error.message);
  }
};

//删除选中编号
const delNoList = async () => {
  try {
    const res = await deleteSateNoList({ norad_id: curSelSateNo.value });
    if (res.code === 0) {
      ElMessage.success("删除编号成功");
    }
    resetSelected.value = true;
    curSelSateNo.value = [];
    nextTick(() => {
      resetSelected.value = false;
    });
    getSateNoList();
  } catch (error: any) {
    ElMessage.error(error.message);
  }
};

const noContentRef = ref<HTMLDivElement | null>(null);

//新添加滚动到底部
const scrollToBottom = () => {
  nextTick(() => {
    const container = noContentRef.value;
    if (container) {
      container.scrollTop = container.scrollHeight - container.clientHeight;
    }
  });
};

//检查输入的编号个数不大于6
const checkNoLeSix = (no: number | string): boolean => {
  if (String(no).length > 6) {
    ElMessage.error("编号位数错误，长度不能大于6位");
    return false;
  }
  return true;
};

const handleNumInput = (value: string) => {
  const filtered = value.replace(/\D/g, "");
  curSateNo.value = filtered.slice(0, 6);
};

const handleEditSateId = async () => {
  editDialogVisible.value = true;
  getSateNoList();
};

//获取编号列表
const getSateNoList = async () => {
  try {
    const res = await getSateIdList();
    if (res.code === 0) {
      sateNoList.value = res.data.list || [];
    }
  } catch (error: any) {
    ElMessage.error(error.message);
  }
};

//读取文本文件后存储读取的编号
const textFileNumbers = ref<string[]>([]);

//监听导入文件的数组变化
watch(textFileNumbers, (newVal) => {
  if (newVal.length > 0) {
    newVal.forEach((num) => {});
    fileImptAddNoList();
  }
});

//判断上传文件类型
const beforeUpload: UploadProps["beforeUpload"] = (rawFile: UploadRawFile) => {
  // 检查文件是否存在
  if (!rawFile) {
    ElMessage.error("请选择文件");
    return Promise.reject();
  }
  // 检查文件类型
  const isTxtType = rawFile.type === "text/plain";
  // 检查文件后缀名
  const fileName = rawFile.name;
  const isTxtExt = fileName.lastIndexOf(".") > 0 && fileName.slice(fileName.lastIndexOf(".")).toLowerCase() === ".txt";
  // 如果两种检查都不通过
  if (!isTxtType && !isTxtExt) {
    ElMessage.error("只能上传 .txt 格式的文件！");
    //阻止上传
    return Promise.reject();
  }
  // 校验通过
  return true;
};

//处理文件上传
const handleFileChange: UploadProps["onChange"] = (uploadFile) => {
  //清空之前的值
  textFileNumbers.value = [];
  //获取原生file对象
  const file = uploadFile.raw;
  if (!file || !(file instanceof File)) {
    ElMessage.error("未获取到有效文件");
    return;
  }
  //验证文件类型
  if (file.type !== "text/plain" && !file.name.endsWith(".txt")) {
    ElMessage.error("请上传.txt文件");
  }
  //使用FileReader读取文件内容
  const reader = new FileReader();
  //成功的回调
  reader.onload = (event: ProgressEvent<FileReader>) => {
    const textContent = event.target?.result as string;
    if (!textContent) {
      throw new Error("文件内容为空");
    }
    textFileNumbers.value = parseTextToNumbers(textContent).map((item) => String(item));
  };
  //失败的回调
  reader.onerror = () => {
    ElMessage.error("文件导入失败，请检查文件是否损坏或重试");
  };
  //读取文件
  reader.readAsText(file, "utf-8");
};

//解析文件内容
const parseTextToNumbers = (text: string): number[] => {
  if (!text) return [];
  //换行符分割
  const lines = text.split(/\r?\n/);
  //遍历处理
  const numbers = lines
    .map((line) => {
      //去除首尾空格
      const trimmedLine = line.trim();
      if (trimmedLine === "") return null;
      const number = Number(trimmedLine);
      if (isNaN(number)) {
        return null;
      }
      return number;
    })
    .filter((num): num is number => num !== null);

  return numbers;
};

onMounted(() => {
  getData();
});
</script>

<style scoped>
:deep(.el-input__inner) {
  color: black;
}
/* 去除按钮边框 */
.el-button:focus {
  outline: none;
}

.table-content {
  padding: 10px;
  margin-top: 30px;
  background: rgba(255, 255, 255, 0.03);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(78, 237, 255, 0.2);
  box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
  border-radius: 8px;
  padding: 15px;
}

.title {
  text-align: left;
  font-size: 18px;
  font-weight: 500;
  color: white;
}

.btns {
  display: flex;
  gap: 10px;
}

.low-titme {
  color: #ccc;
  text-align: left;
  margin-left: 20px;
}
.divider {
  margin-top: 15px;
}

.No-Content {
  width: 100%;
  height: 200px;
  background-color: #1d5484;
  border: 4px solid #083b67;
  display: flex;
  padding: 10px;
  box-sizing: border-box;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  overflow-x: hidden;
}

.footer {
  margin-top: 20px;
  display: flex;
  justify-content: space-between;
}

.No {
  display: flex;
  align-items: center;
}

.No-Content::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

.No-Content::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.No-Content::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
  box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.1);
}

.No-Content::-webkit-scrollbar-thumb:hover {
  background: #999;
}

.No-Content::-webkit-scrollbar-button {
  display: none;
}

.No-Content {
  scrollbar-width: thin;
  scrollbar-color: #c1c1c1 #f1f1f1;
}

.btn-group {
  display: flex;
  gap: 8px;
  white-space: nowrap;
  justify-content: center;
}
.btn-group .el-button {
  flex-shrink: 0;
}
</style>
