<!-- eslint-disable no-use-before-define -->
<script setup lang="ts">
import type { TaskInfo } from '#/api/workflow/task/model';

import { computed, onMounted, ref, useTemplateRef } from 'vue';

import { Page } from '@vben/common-ui';
import { DictEnum } from '@vben/constants';
import { useTabs } from '@vben/hooks';

import { Refresh, Search } from '@element-plus/icons-vue';
import {
  ElButton,
  ElEmpty,
  ElInput,
  ElMessage,
  ElOption,
  ElSelect,
  ElTooltip,
} from 'element-plus';
import { cloneDeep, debounce } from 'lodash-es';

import { pageByCurrent } from '#/api/workflow/instance';
import { getDictOptions } from '#/utils/dict';

import { ApprovalCard, ApprovalPanel } from '../components';
import { bottomOffset } from './constant';

const emptyImage = ElEmpty.PRESENTED_IMAGE_SIMPLE;

const taskList = ref<(TaskInfo & { active: boolean })[]>([]);
const taskTotal = ref(0);
const page = ref(1);
const loading = ref(false);

const defaultFormData = {
  searchKeyword: '', // 通用搜索关键词
  status: null as null | number, // 工单状态
};
const formData = ref(cloneDeep(defaultFormData));

/**
 * 是否已经加载全部数据 即 taskList.length === taskTotal
 */
const isLoadComplete = computed(
  () => taskList.value.length === taskTotal.value,
);

// 获取状态下拉框选项
const statusOptions = getDictOptions(DictEnum.TICKET_STATUS);

// 卡片父容器的ref
const cardContainerRef = useTemplateRef('cardContainerRef');

/**
 * @param resetFields 是否清空查询参数
 */
async function reload(resetFields: boolean = false) {
  // 需要先滚动到顶部
  cardContainerRef.value?.scroll({ top: 0, behavior: 'auto' });

  page.value = 1;
  currentWorkOrderDetail.value = undefined;
  taskTotal.value = 0;
  lastSelectId.value = '';

  if (resetFields) {
    formData.value = cloneDeep(defaultFormData);
  }

  loading.value = true;
  try {
    // 根据搜索关键词类型动态决定搜索字段
    const searchParams = { ...formData.value };
    const { searchKeyword, ...otherParams } = searchParams;

    // 如果有搜索关键词
    if (searchKeyword) {
      // 检查是否为数字
      if (/^\d+$/.test(searchKeyword)) {
        // 数字搜索orderNo
        otherParams.orderNo = searchKeyword;
      } else {
        // 文字搜索content
        otherParams.content = searchKeyword;
      }
    }

    const resp = await pageByCurrent({
      pageSize: 10,
      pageNum: page.value,
      ...otherParams,
    });
    taskList.value = resp.rows.map((item) => ({
      ...item,
      active: false,
      id: String(item.id),
    }));
    taskTotal.value = resp.total;
  } catch {
    ElMessage.error('加载任务列表失败');
  } finally {
    loading.value = false;
  }

  // 默认选中第一个
  if (taskList.value.length > 0) {
    const firstTask = taskList.value[0]!;
    currentWorkOrderDetail.value = firstTask;
    handleCardClick(firstTask);
  }
}

onMounted(reload);

const handleScroll = debounce(async (e: Event) => {
  if (!e.target) {
    return;
  }
  // e.target.scrollTop 是元素顶部到当前可视区域顶部的距离，即已滚动的高度。
  // e.target.clientHeight 是元素的可视高度。
  // e.target.scrollHeight 是元素的总高度。
  const { scrollTop, clientHeight, scrollHeight } = e.target as HTMLElement;
  // 判断是否滚动到底部
  const isBottom = scrollTop + clientHeight >= scrollHeight - bottomOffset;

  // 滚动到底部且没有加载完成
  if (isBottom && !isLoadComplete.value) {
    loading.value = true;
    try {
      page.value += 1;

      // 根据搜索关键词类型动态决定搜索字段
      const searchParams = { ...formData.value };
      const { searchKeyword, ...otherParams } = searchParams;

      // 如果有搜索关键词
      if (searchKeyword) {
        // 检查是否为数字
        if (/^\d+$/.test(searchKeyword)) {
          // 数字搜索orderNo
          otherParams.orderNo = searchKeyword;
        } else {
          // 文字搜索content
          otherParams.content = searchKeyword;
        }
      }

      const resp = await pageByCurrent({
        pageSize: 10,
        pageNum: page.value,
        ...otherParams,
      });
      taskList.value.push(
        ...resp.rows.map((item) => ({
          ...item,
          active: false,
          id: String(item.id),
        })),
      );
    } catch {
      ElMessage.error('加载更多任务失败');
    } finally {
      loading.value = false;
    }
  }
}, 200);

const lastSelectId = ref('');
const currentWorkOrderDetail = ref<any>();
async function handleCardClick(item: TaskInfo) {
  const { id } = item;
  // 点击的是同一个
  if (lastSelectId.value === id) {
    return;
  }
  currentWorkOrderDetail.value = item;
  // 反选状态 & 如果已经点击了 不变 & 保持只能有一个选中
  taskList.value.forEach((item) => {
    item.active = item.id === id;
  });
  lastSelectId.value = id;
}

const { refreshTab } = useTabs();

// 按钮权限控制
const currentTaskButtonPermissions = computed(() => {
  // 如果没有当前任务，返回空对象
  if (!currentWorkOrderDetail.value) {
    return {};
  }
  // 根据任务状态判断工单类型
  const { status } = currentWorkOrderDetail.value;
  // 初始化权限对象
  const permissions: Record<string, boolean> = {};
  // 新工单 (status: "news")
  if (status === 'new') {
    // 新工单可以进行的操作
    permissions.edit = true; // 编辑
    permissions.submit = true; // 提交
    permissions.delete = true; // 删除
  }
  // 已处理工单 (status: "processed")
  else if (status === 'processed') {
    // 已处理工单可以进行的操作
    permissions.edit = false; // 编辑
    permissions.submit = false; // 提交
    permissions.delete = false; // 删除
  }
  return permissions;
});
</script>

<template>
  <Page :auto-content-height="true">
    <div class="flex h-full gap-2">
      <div
        class="bg-background relative flex h-full min-w-[320px] max-w-[320px] flex-col rounded-lg"
      >
        <!-- 搜索条件 -->
        <div
          class="bg-background z-100 sticky left-0 top-0 w-full rounded-t-lg border-b-[1px] border-solid p-2"
        >
          <div class="grid grid-cols-1 gap-2">
            <div class="flex items-center gap-1">
              <ElInput
                v-model="formData.searchKeyword"
                placeholder="输入数字搜索工单号，输入文字搜索内容"
                clearable
                class="w-full"
                :suffix-icon="Search"
                @keyup.enter="reload(false)"
              />
            </div>
            <div class="flex items-center gap-1">
              <ElSelect
                v-model="formData.status"
                placeholder="状态"
                clearable
                class="w-full"
                @change="reload(false)"
              >
                <ElOption
                  v-for="option in statusOptions"
                  :key="option.value"
                  :label="option.label"
                  :value="option.value"
                />
              </ElSelect>
              <ElTooltip placement="top" content="重置">
                <ElButton @click="reload(true)" :icon="Refresh" />
              </ElTooltip>
            </div>
          </div>
        </div>
        <div
          ref="cardContainerRef"
          class="thin-scrollbar flex flex-1 flex-col gap-2 overflow-y-auto py-3"
          @scroll="handleScroll"
        >
          <template v-if="taskList.length > 0">
            <ApprovalCard
              v-for="item in taskList"
              :key="item.id"
              :info="item"
              class="mx-2"
              @click="handleCardClick(item)"
            />
          </template>
          <ElEmpty v-else :image="emptyImage" description="暂无数据" />
          <div
            v-if="isLoadComplete && taskList.length > 0"
            class="flex items-center justify-center text-[14px] opacity-50"
          >
            没有更多数据了
          </div>
          <!-- 遮罩loading层 -->
          <div
            v-if="loading"
            class="absolute left-0 top-0 flex h-full w-full items-center justify-center bg-[rgba(0,0,0,0.1)]"
          ></div>
        </div>
        <!-- total显示 -->
        <div
          class="bg-background sticky bottom-0 w-full rounded-b-lg border-t-[1px] py-2"
        >
          <div class="flex items-center justify-center">
            共 {{ taskTotal }} 条记录
          </div>
        </div>
      </div>
      <ApprovalPanel
        :work-order-detail="currentWorkOrderDetail"
        :button-permissions="currentTaskButtonPermissions"
        type="myself"
        @reload="refreshTab"
      />
    </div>
  </Page>
</template>

<style lang="scss" scoped>
.thin-scrollbar {
  &::-webkit-scrollbar {
    width: 5px;
  }
}

:deep(.el-card__body) {
  @apply thin-scrollbar;
}
</style>
