<script lang="ts" setup>
/**
 * 队列任务详情：展示 payload、错误信息、重跑链路；失败/取消可重跑
 * 供队列列表与站内信 queue_failure 共用
 */
import { computed, ref } from 'vue';

import { useVbenModal } from '@vben/common-ui';

import { Button, Descriptions, Modal, Tag, message } from 'ant-design-vue';

import { getQueueJobDetail, retryQueueJob } from '../api';
import { statusTagColor } from '../config/constants';

const data = ref<Record<string, any>>({});
const loading = ref(false);
const retrying = ref(false);
const onRetried = ref<null | (() => void)>(null);

function formatJson(val: unknown): string {
  if (val == null || val === '') {
    return '（无）';
  }
  try {
    return JSON.stringify(val, null, 2);
  } catch {
    return String(val);
  }
}

const canRetry = computed(() => {
  const status = Number(data.value?.status);
  return status === 3 || status === 4;
});

const [ModalComp, modalApi] = useVbenModal({
  fullscreenButton: true,
  draggable: true,
  showConfirmButton: false,
  cancelText: '关闭',
  onCancel() {
    modalApi.close();
  },
  async onOpenChange(isOpen: boolean) {
    if (!isOpen) {
      data.value = {};
      onRetried.value = null;
      return;
    }
    const payload = modalApi.getData<{
      id?: number;
      values?: Record<string, any>;
      onRetried?: () => void;
    }>();
    onRetried.value = payload?.onRetried || null;
    const id = Number(payload?.id || payload?.values?.id || 0);
    if (id <= 0) {
      data.value = payload?.values || {};
      return;
    }
    loading.value = true;
    modalApi.setState({ loading: true });
    try {
      const res = await getQueueJobDetail(id);
      data.value = res?.data || res || {};
    } catch {
      data.value = payload?.values || {};
    } finally {
      loading.value = false;
      modalApi.setState({ loading: false });
    }
  },
});

/**
 * 失败/取消后重跑：新建任务投递，与列表页逻辑一致
 */
function onRetry() {
  const id = Number(data.value?.id || 0);
  if (id <= 0) return;
  Modal.confirm({
    title: '确认重新执行？',
    content:
      `将基于 #${id} 新建一条任务并重新投递。` +
      '订单/退款等业务重跑可能产生副作用，请确认业务幂等后再操作。',
    okType: 'danger',
    onOk: async () => {
      retrying.value = true;
      try {
        const res = await retryQueueJob(id);
        const newId = res?.id ?? res?.data?.id;
        message.success(newId ? `已重新投递，新任务 #${newId}` : '已重新投递');
        onRetried.value?.();
        // 刷新当前详情（原任务状态可能仍失败，链路会多一条）
        const detail = await getQueueJobDetail(id);
        data.value = detail?.data || detail || data.value;
      } finally {
        retrying.value = false;
      }
    },
  });
}
</script>

<template>
  <ModalComp class="w-[90%] md:w-[780px]" title="队列任务详情">
    <Descriptions
      :column="{ xxl: 2, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }"
      bordered
      size="small"
    >
      <Descriptions.Item label="ID">{{ data.id }}</Descriptions.Item>
      <Descriptions.Item label="状态">
        <Tag :color="statusTagColor(Number(data.status))">
          {{ data.status_txt || data.status }}
        </Tag>
      </Descriptions.Item>
      <Descriptions.Item label="标题" :span="2">
        {{ data.title || '-' }}
      </Descriptions.Item>
      <Descriptions.Item label="任务类型">
        {{ data.job_name_txt || '-' }}
      </Descriptions.Item>
      <Descriptions.Item label="分类">
        {{ data.category_txt || data.category }}
      </Descriptions.Item>
      <Descriptions.Item label="操作人">
        {{ data.user_name || '-' }}（ID: {{ data.user_id || 0 }}）
      </Descriptions.Item>
      <Descriptions.Item label="耗时">
        {{ data.time_difference || '-' }}
      </Descriptions.Item>
      <Descriptions.Item label="创建时间">
        {{ data.created_at || '-' }}
      </Descriptions.Item>
      <Descriptions.Item label="执行时间">
        {{ data.available_at || data.created_at || '-' }}
        <Tag v-if="Number(data.is_delayed) === 1" color="purple" class="ml-1">
          延迟
        </Tag>
        <span
          v-if="Number(data.is_delayed) === 1 && Number(data.delay_seconds) > 0"
          class="ml-1 text-xs text-muted-foreground"
        >
          （相对创建 {{ data.delay_type_txt || '延迟' }}）
        </span>
      </Descriptions.Item>
      <Descriptions.Item label="更新时间">
        {{ data.updated_at || '-' }}
      </Descriptions.Item>
      <Descriptions.Item label="简介" :span="2">
        {{ data.detail || '-' }}
      </Descriptions.Item>
      <Descriptions.Item label="任务类名" :span="2">
        <code class="break-all text-xs">{{ data.job_name || '-' }}</code>
      </Descriptions.Item>
      <Descriptions.Item label="错误信息" :span="2">
        <pre class="snap-pre error-pre">{{ data.error_message || '（无）' }}</pre>
      </Descriptions.Item>
      <Descriptions.Item label="重跑参数 payload" :span="2">
        <pre class="snap-pre">{{ formatJson(data.payload) }}</pre>
      </Descriptions.Item>
      <Descriptions.Item label="重跑链路" :span="2">
        <div v-if="Array.isArray(data.retry_chain) && data.retry_chain.length">
          <div
            v-for="item in data.retry_chain"
            :key="item.id"
            class="mb-1 text-xs"
          >
            #{{ item.id }}
            <Tag :color="statusTagColor(Number(item.status))" class="mx-1">
              {{ item.status_txt }}
            </Tag>
            {{ item.title }}
            <span class="text-muted-foreground">{{ item.created_at }}</span>
            <span v-if="item.retry_from_id" class="text-muted-foreground">
              （来自 #{{ item.retry_from_id }}）
            </span>
          </div>
        </div>
        <span v-else>-</span>
      </Descriptions.Item>
    </Descriptions>

    <div v-if="canRetry" class="mt-4 flex justify-end">
      <Button type="primary" danger :loading="retrying" @click="onRetry">
        重新执行
      </Button>
    </div>
  </ModalComp>
</template>

<style scoped>
.snap-pre {
  margin: 0;
  max-height: 280px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
  font-size: 12px;
  line-height: 1.5;
  color: hsl(var(--foreground));
}

.error-pre {
  max-height: 200px;
  padding: 8px 10px;
  border-radius: 8px;
  background: hsl(0 72% 50% / 0.08);
  color: hsl(0 72% 40%);
}
</style>
