<template>
  <el-dialog v-model="visibleProxy" title="执行日志详情" width="80%" append-to-body :close-on-click-modal="false">
    <el-card v-loading="loading" class="log-detail-card">
      <template #header>
        <div class="flex justify-between items-center">
          <span>日志详情</span>
          <div>
            <el-button type="primary" icon="Refresh" size="small" @click="refreshLog">刷新</el-button>
            <el-button type="success" icon="Download" size="small" @click="downloadLog">下载</el-button>
          </div>
        </div>
      </template>

      <!-- 基本信息 -->
      <div v-if="logDetail" class="log-info mb-4">
        <el-descriptions :column="2" border>
          <el-descriptions-item label="执行器地址">{{ logDetail.executorAddress || '-' }}</el-descriptions-item>
          <el-descriptions-item label="调度结果">
            <el-tag :type="getStatusType(logDetail.triggerCode)">
              {{ getStatusText(logDetail.triggerCode) }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="调度备注" :span="2">
            <div class="max-h-20 overflow-auto">{{ logDetail.triggerMsg || '-' }}</div>
          </el-descriptions-item>
          <el-descriptions-item v-if="logDetail.handleCode" label="执行结果">
            <el-tag :type="getStatusType(logDetail.handleCode)">
              {{ getStatusText(logDetail.handleCode) }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item v-if="logDetail.handleMsg" label="执行备注">
            <div class="max-h-20 overflow-auto">{{ logDetail.handleMsg || '-' }}</div>
          </el-descriptions-item>
        </el-descriptions>
      </div>

      <!-- 执行日志内容 -->
      <div class="log-content">
        <div class="log-header flex justify-between items-center mb-2">
          <span class="font-semibold">执行日志：</span>
          <div class="flex items-center space-x-2">
            <el-switch v-model="autoRefresh" active-text="自动刷新" @change="handleAutoRefreshChange" />
            <span class="text-sm text-gray-500">共 {{ logLines.length }} 行</span>
          </div>
        </div>

        <div ref="logViewerRef" class="log-viewer">
          <div v-for="(line, index) in logLines" :key="index" class="log-line" :class="getLogLineClass(line)">
            <span class="line-number">{{ index + 1 }}</span>
            <span class="line-content">{{ line }}</span>
          </div>
          <div v-if="logLines.length === 0" class="text-center text-gray-500 py-8">暂无日志内容</div>
        </div>
      </div>
    </el-card>
  </el-dialog>
</template>

<script setup lang="ts">
import { getJobLogDetail, getJobLogContent } from '@/api/xxljob/log';
import { JobLogDetail, LogStatus } from '@/api/xxljob/log/types';

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  logId: {
    type: [String, Number],
    required: true
  }
});

const emit = defineEmits(['update:visible']);

// 可见性的双向绑定
const visibleProxy = computed({
  get: () => props.visible,
  set: (val) => emit('update:visible', val)
});

const loading = ref(false);
const autoRefresh = ref(false);
const logDetail = ref<JobLogDetail | null>(null);
const logLines = ref<string[]>([]);
const logViewerRef = ref<HTMLElement>();
let refreshTimer: NodeJS.Timeout | null = null;

/** 获取状态类型 */
const getStatusType = (code: number) => {
  switch (code) {
    case LogStatus.SUCCESS:
      return 'success';
    case LogStatus.FAIL:
      return 'danger';
    case LogStatus.RUNNING:
      return 'warning';
    default:
      return 'info';
  }
};

/** 获取状态文本 */
const getStatusText = (code: number) => {
  switch (code) {
    case LogStatus.SUCCESS:
      return '成功';
    case LogStatus.FAIL:
      return '失败';
    case LogStatus.RUNNING:
      return '进行中';
    default:
      return '未知';
  }
};

/** 获取日志行样式 */
const getLogLineClass = (line: string) => {
  if (line.includes('[ERROR]') || line.includes('ERROR')) {
    return 'log-error';
  } else if (line.includes('[WARN]') || line.includes('WARN')) {
    return 'log-warn';
  } else if (line.includes('[INFO]') || line.includes('INFO')) {
    return 'log-info';
  } else if (line.includes('[DEBUG]') || line.includes('DEBUG')) {
    return 'log-debug';
  }
  return '';
};

/** 加载日志详情 */
const loadLogDetail = async () => {
  if (!props.logId) return;

  loading.value = true;
  try {
    // 获取日志基本信息
    const detailRes = await getJobLogDetail(props.logId);
    logDetail.value = detailRes.data;

    // 获取日志内容
    const contentRes = await getJobLogContent(props.logId);
    if (contentRes.data && contentRes.data.logContent) {
      logLines.value = contentRes.data.logContent.split('\n').filter((line) => line.trim());
    } else {
      logLines.value = [];
    }

    // 滚动到底部
    nextTick(() => {
      scrollToBottom();
    });
  } catch (error) {
    logLines.value = [];
  } finally {
    loading.value = false;
  }
};

/** 刷新日志 */
const refreshLog = () => {
  loadLogDetail();
};

/** 滚动到底部 */
const scrollToBottom = () => {
  if (logViewerRef.value) {
    logViewerRef.value.scrollTop = logViewerRef.value.scrollHeight;
  }
};

/** 处理自动刷新开关 */
const handleAutoRefreshChange = (enabled: boolean) => {
  if (enabled) {
    refreshTimer = setInterval(() => {
      loadLogDetail();
    }, 3000); // 每3秒刷新一次
  } else {
    if (refreshTimer) {
      clearInterval(refreshTimer);
      refreshTimer = null;
    }
  }
};

/** 下载日志 */
const downloadLog = () => {
  if (logLines.value.length === 0) {
    ElMessage.warning('暂无日志内容可下载');
    return;
  }

  const content = logLines.value.join('\n');
  const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = `job_log_${props.logId}_${Date.now()}.txt`;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
};

// 监听对话框显示状态
watch(
  () => props.visible,
  (visible) => {
    if (visible) {
      loadLogDetail();
    } else {
      // 关闭时清理定时器
      if (refreshTimer) {
        clearInterval(refreshTimer);
        refreshTimer = null;
      }
      autoRefresh.value = false;
    }
  }
);

// 组件卸载时清理定时器
onUnmounted(() => {
  if (refreshTimer) {
    clearInterval(refreshTimer);
  }
});
</script>

<style scoped>
.log-detail-card {
  height: 70vh;
  display: flex;
  flex-direction: column;
}

.log-detail-card :deep(.el-card__body) {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.log-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.log-viewer {
  flex: 1;
  background-color: #1e1e1e;
  color: #d4d4d4;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 12px;
  padding: 10px;
  overflow-y: auto;
  border-radius: 4px;
  border: 1px solid #e4e7ed;
}

.log-line {
  display: flex;
  padding: 2px 0;
  border-left: 3px solid transparent;
}

.log-line:hover {
  background-color: rgba(255, 255, 255, 0.05);
}

.line-number {
  color: #858585;
  min-width: 50px;
  text-align: right;
  margin-right: 10px;
  user-select: none;
}

.line-content {
  flex: 1;
  word-break: break-all;
}

.log-error {
  color: #f56565;
  border-left-color: #f56565;
}

.log-warn {
  color: #ed8936;
  border-left-color: #ed8936;
}

.log-info {
  color: #4299e1;
  border-left-color: #4299e1;
}

.log-debug {
  color: #9f7aea;
  border-left-color: #9f7aea;
}
</style>
