<script setup lang="ts">
/**
 * 发布执行详情聚合 run 元数据、步骤摘要和按需读取的 Jenkins build 日志。
 */
import { RefreshRight, Tickets } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { computed, ref, watch } from 'vue'
import { devopsApi } from '../services/devopsApi'
import type { JenkinsBuildLog, ReleaseRun } from '../types/devops'
import StatusPill from './StatusPill.vue'

const props = defineProps<{
  run: ReleaseRun
}>()

const logVisible = ref(false)
const logLoading = ref(false)
const logText = ref('')
const logMeta = ref<JenkinsBuildLog | null>(null)

const notableSteps = computed(() =>
  props.run.steps.filter(
    (step) =>
      step.status === 'failed' ||
      step.status === 'skipped' ||
      step.errorSummary ||
      step.message ||
      step.logExcerpt,
  ),
)

const canReadJenkinsLog = computed(
  () => props.run.jenkinsBuildNumber !== undefined && props.run.jenkinsBuildNumber !== null,
)

const logTitle = computed(() => {
  const buildNumber = props.run.jenkinsBuildNumber

  return buildNumber ? `Jenkins 日志 #${buildNumber}` : 'Jenkins 日志'
})

function noteLabel(status: string) {
  return status === 'failed' ? '失败摘要' : '执行提示'
}

function displayText(value?: string | number) {
  if (value === undefined || value === null || value === '' || value === '-') {
    return '未返回'
  }

  return String(value)
}

function finishText() {
  if (props.run.finishedAt && props.run.finishedAt !== '-') {
    return props.run.finishedAt
  }

  if (props.run.status === 'queued' || props.run.status === 'running') {
    return '未结束'
  }

  return '未返回'
}

function buildText() {
  if (props.run.jenkinsBuildNumber !== undefined && props.run.jenkinsBuildNumber !== null) {
    return `#${props.run.jenkinsBuildNumber}`
  }

  return '未返回'
}

function resetJenkinsLog() {
  logVisible.value = false
  logLoading.value = false
  logText.value = ''
  logMeta.value = null
}

async function openJenkinsLog() {
  if (!canReadJenkinsLog.value) {
    ElMessage.warning('当前发布单尚未关联 Jenkins build')
    return
  }

  logVisible.value = true

  if (!logText.value) {
    await loadJenkinsLog(0)
  }
}

async function reloadJenkinsLog() {
  await loadJenkinsLog(0)
}

async function loadMoreJenkinsLog() {
  await loadJenkinsLog(logMeta.value?.nextStart ?? 0)
}

async function loadJenkinsLog(start: number) {
  logLoading.value = true
  try {
    const log = await devopsApi.getJenkinsLog(props.run.id, start)
    logMeta.value = log
    logText.value = start === 0 ? log.text : `${logText.value}${log.text}`
  } finally {
    logLoading.value = false
  }
}

watch(() => props.run.id, resetJenkinsLog)
</script>

<template>
  <div class="run-execution-details">
    <dl class="detail-grid">
      <dt>Run ID</dt>
      <dd class="mono">{{ displayText(run.id) }}</dd>
      <dt>项目</dt>
      <dd>{{ displayText(run.projectName) }}</dd>
      <dt>环境</dt>
      <dd>{{ displayText(run.environment) }}</dd>
      <dt>ref/tag</dt>
      <dd class="mono">{{ displayText(run.ref) }}</dd>
      <dt>操作者</dt>
      <dd>{{ displayText(run.actor) }}</dd>
      <dt>状态</dt>
      <dd><StatusPill :state="run.status" /></dd>
      <dt>开始时间</dt>
      <dd>{{ displayText(run.startedAt) }}</dd>
      <dt>结束时间</dt>
      <dd>{{ finishText() }}</dd>
      <dt>Jenkins Queue</dt>
      <dd class="mono">{{ displayText(run.jenkinsQueueId) }}</dd>
      <dt>Jenkins Build</dt>
      <dd class="mono">{{ buildText() }}</dd>
      <dt>Jenkins 日志</dt>
      <dd>
        <ElButton
          size="small"
          :icon="Tickets"
          :disabled="!canReadJenkinsLog"
          :loading="logLoading"
          @click="openJenkinsLog"
        >
          查看日志
        </ElButton>
      </dd>
      <dt>Jenkins 状态</dt>
      <dd>{{ displayText(run.jenkinsSummary) }}</dd>
      <dt>Build URL</dt>
      <dd>
        <a v-if="run.jenkinsBuildUrl" :href="run.jenkinsBuildUrl" target="_blank" rel="noreferrer">
          {{ run.jenkinsBuildUrl }}
        </a>
        <span v-else>未返回</span>
      </dd>
      <dt>Commit</dt>
      <dd>{{ displayText(run.commitSummary) }}</dd>
      <dt>备注</dt>
      <dd>{{ displayText(run.note) }}</dd>
    </dl>

    <div class="failure-block">
      <div class="failure-header">
        <strong>执行提示 / 日志摘要</strong>
        <span>{{ notableSteps.length ? `${notableSteps.length} 个节点` : '未返回异常或提示' }}</span>
      </div>
      <div v-if="notableSteps.length" class="failure-list">
        <article
          v-for="step in notableSteps"
          :key="step.id"
          class="failure-item"
          :class="{ danger: step.status === 'failed' }"
        >
          <div class="failure-title">
            <strong>{{ step.name }}</strong>
            <StatusPill :state="step.status" />
          </div>
          <p v-if="step.errorSummary">
            <span>{{ noteLabel(step.status) }}</span>
            {{ step.errorSummary }}
          </p>
          <p v-if="step.message">
            <span>执行消息</span>
            {{ step.message }}
          </p>
          <pre v-if="step.logExcerpt">{{ step.logExcerpt }}</pre>
          <p v-if="!step.errorSummary && !step.message && !step.logExcerpt">
            <span>节点摘要</span>
            {{ step.summary }}
          </p>
        </article>
      </div>
      <div v-else class="empty-line">后端尚未返回异常摘要、执行提示或日志摘要。</div>
    </div>

    <ElDrawer v-model="logVisible" :title="logTitle" size="min(760px, 92vw)" append-to-body>
      <div class="jenkins-log-drawer">
        <div class="jenkins-log-toolbar">
          <span>
            {{ logMeta ? `${logMeta.jobPath} · start ${logMeta.start} -> ${logMeta.nextStart}` : '等待读取' }}
          </span>
          <div class="log-actions">
            <ElButton size="small" :icon="RefreshRight" :loading="logLoading" @click="reloadJenkinsLog">
              重新读取
            </ElButton>
            <ElButton
              v-if="logMeta?.hasMore"
              size="small"
              :loading="logLoading"
              @click="loadMoreJenkinsLog"
            >
              继续加载
            </ElButton>
          </div>
        </div>
        <pre v-if="logText" class="jenkins-log-output">{{ logText }}</pre>
        <div v-else class="empty-line">Jenkins 暂无日志。</div>
      </div>
    </ElDrawer>
  </div>
</template>

<style scoped>
.run-execution-details {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.detail-grid {
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr);
  gap: 10px 12px;
  margin: 0;
  font-size: 13px;
}

.detail-grid dt {
  color: #7b8798;
}

.detail-grid dd {
  margin: 0;
  min-width: 0;
  color: #172033;
  overflow-wrap: anywhere;
}

.detail-grid a {
  color: #1d5fd0;
}

.detail-grid :deep(.el-button) {
  max-width: 100%;
}

.failure-block {
  border-top: 1px solid #edf1f7;
  padding-top: 14px;
}

.failure-header,
.failure-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.failure-header strong,
.failure-title strong {
  color: #172033;
  font-size: 13px;
}

.failure-header span {
  color: #7b8798;
  font-size: 12px;
}

.failure-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
}

.failure-item {
  padding: 10px 12px;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  background: #fbfcff;
}

.failure-item.danger {
  border-color: #f0d5d5;
  background: #fffafa;
}

.failure-item p {
  margin: 8px 0 0;
  color: #4b5565;
  font-size: 13px;
  line-height: 1.6;
}

.failure-item p span {
  display: inline-block;
  margin-right: 8px;
  color: #62572c;
  font-weight: 600;
}

.failure-item.danger p span {
  color: #9f2f2f;
}

.failure-item pre {
  max-height: 180px;
  margin: 10px 0 0;
  padding: 10px;
  overflow: auto;
  border-radius: 6px;
  background: #172033;
  color: #eef4ff;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
}

.empty-line {
  margin-top: 10px;
  color: #7b8798;
  font-size: 13px;
}

.jenkins-log-drawer {
  display: flex;
  min-height: 100%;
  flex-direction: column;
  gap: 12px;
}

.jenkins-log-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: #5f6b7a;
  font-size: 12px;
}

.log-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.jenkins-log-output {
  flex: 1;
  min-height: 420px;
  margin: 0;
  padding: 12px;
  overflow: auto;
  border-radius: 6px;
  background: #111827;
  color: #e5edf8;
  font-size: 12px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .detail-grid {
    grid-template-columns: 1fr;
    gap: 4px 0;
  }

  .detail-grid dd + dt {
    margin-top: 8px;
  }

  .jenkins-log-toolbar {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>
