<template>
  <article
    v-if="loading || error || releaseState || reviewQueue"
    class="detail-card panel release-monitor-card"
  >
    <div class="release-monitor-head">
      <div>
        <p class="release-monitor-eyebrow">AI 发布控制</p>
        <h3>真实运行遥测与独立盲审</h3>
        <p>正负样本随机混排，候选与基线结论对复核人隐藏；证据不足时不会自动晋级。</p>
      </div>
      <button type="button" class="release-refresh" :disabled="loading" @click="emit('refresh')">
        <i class="mdi mdi-refresh" :class="{ spinning: loading }"></i>
        <span>刷新</span>
      </button>
    </div>

    <div v-if="loading && !reviewQueue" class="release-state-note" role="status">
      正在聚合当前发布阶段的真实样本…
    </div>
    <div v-else-if="error" class="release-state-note error" role="alert">{{ error }}</div>

    <template v-if="releaseState || reviewQueue">
      <div class="release-identity">
        <span :class="['release-stage', stageTone]">{{ stageLabel }}</span>
        <span>候选版本 {{ reviewQueue?.version || releaseState?.candidate_version || '-' }}</span>
        <span>稳定版本 {{ releaseState?.previous_version || '-' }}</span>
        <span>{{ telemetryLabel }}</span>
      </div>

      <div class="release-metric-grid">
        <div v-for="metric in metricCards" :key="metric.label" class="release-metric">
          <span>{{ metric.label }}</span>
          <strong>{{ metric.value }}</strong>
          <small>{{ metric.hint }}</small>
        </div>
      </div>

      <div v-if="reviewQueue?.alerts?.length" class="release-alert-list" aria-label="发布告警">
        <div
          v-for="alert in reviewQueue.alerts"
          :key="alert.code"
          :class="['release-alert', `is-${alert.severity}`]"
        >
          <i class="mdi mdi-alert-circle-outline"></i>
          <div>
            <strong>{{ alert.message }}</strong>
            <span>{{ alert.recommended_action }}</span>
          </div>
        </div>
      </div>

      <section class="release-review-section">
        <div class="release-review-title">
          <div>
            <h4>待复核样本</h4>
            <p>发布发起人不能复核自己的版本；请只依据源单据和规则判断是否存在真实风险。</p>
          </div>
          <b>{{ reviewQueue?.pending_total || 0 }} 条</b>
        </div>

        <div v-if="reviewQueue?.items?.length" class="release-review-list">
          <div v-for="item in reviewQueue.items" :key="item.sample_id || item.observation_id" class="release-review-row">
            <div class="release-review-meta">
              <strong>{{ businessStageLabel(item.business_stage) }}</strong>
              <span>{{ formatDate(item.created_at) }}</span>
              <small>
                规则 {{ item.rule_code || '未标识' }} ·
                复核 {{ item.reviewer_count || 0 }}/{{ item.required_reviewers || 1 }}
              </small>
              <small class="release-review-blind">正负样本随机混排 · 模型结论已隐藏</small>
              <RouterLink
                v-if="sourceDocumentRoute(item)"
                class="release-source-link"
                :to="sourceDocumentRoute(item)"
                target="_blank"
                rel="noopener noreferrer"
              >
                <i class="mdi mdi-open-in-new" aria-hidden="true"></i>
                新标签查看源单据
              </RouterLink>
              <small v-if="item.conflicted" class="release-review-conflict">复核结论存在分歧，需要继续仲裁。</small>
            </div>
            <div class="release-review-actions">
              <button
                type="button"
                class="review-decision"
                :disabled="!canReview || Boolean(action)"
                @click="emit('label', item.observation_id, 'risk_present')"
              >
                {{ action === `${item.observation_id}:risk_present` ? '提交中…' : '存在真实风险' }}
              </button>
              <button
                type="button"
                class="review-decision"
                :disabled="!canReview || Boolean(action)"
                @click="emit('label', item.observation_id, 'risk_absent')"
              >
                {{ action === `${item.observation_id}:risk_absent` ? '提交中…' : '确认无该风险' }}
              </button>
            </div>
          </div>
        </div>
        <div v-else class="release-review-empty">
          <i class="mdi mdi-check-decagram-outline"></i>
          <span>当前没有待复核盲审样本；召回率只在正负样本独立标注证据就绪后展示。</span>
        </div>
      </section>
    </template>
  </article>
</template>

<script setup>
import { computed } from 'vue'

import {
  buildReleaseMonitorMetricCards,
  buildReleaseReviewDocumentRoute
} from '../../views/scripts/useAuditReleaseMonitor.js'

const props = defineProps({
  releaseState: { type: Object, default: null },
  reviewQueue: { type: Object, default: null },
  loading: { type: Boolean, default: false },
  error: { type: String, default: '' },
  action: { type: String, default: '' },
  canReview: { type: Boolean, default: false }
})

const emit = defineEmits(['refresh', 'label'])

const stageLabel = computed(() => ({
  shadow: '影子发布',
  canary: '灰度发布',
  active: '正式运行',
  rolled_back: '已回滚'
}[props.releaseState?.stage || props.reviewQueue?.stage] || '未受控'))

const stageTone = computed(() => `is-${props.releaseState?.stage || props.reviewQueue?.stage || 'unknown'}`)
const telemetryLabel = computed(() => (
  props.reviewQueue?.telemetry_status === 'ready' ? '指标已就绪' : '证据采集中'
))

const metricCards = computed(() => buildReleaseMonitorMetricCards(props.reviewQueue || {}))

function sourceDocumentRoute(item) {
  return buildReleaseReviewDocumentRoute(item)
}

function businessStageLabel(value) {
  return value === 'expense_application' ? '费用申请' : '费用报销'
}

function formatDate(value) {
  const date = new Date(value)
  return Number.isNaN(date.getTime()) ? '-' : date.toLocaleString('zh-CN', { hour12: false })
}
</script>

<style scoped>
.release-monitor-card { display: grid; gap: 18px; }
.release-monitor-head, .release-review-title, .release-review-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }
.release-monitor-head h3, .release-review-title h4 { margin: 2px 0 6px; color: var(--text-primary); }
.release-monitor-head p, .release-review-title p { margin: 0; color: var(--text-muted); line-height: 1.6; }
.release-monitor-eyebrow { color: var(--theme-primary) !important; font-size: 12px; font-weight: 800; letter-spacing: .08em; }
.release-refresh { min-height: 44px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line); border-radius: 8px; padding: 0 14px; background: var(--surface); color: var(--text-primary); }
.spinning { animation: spin 800ms linear infinite; }
.release-identity { display: flex; flex-wrap: wrap; gap: 8px; color: var(--text-muted); font-size: 13px; }
.release-identity > span { padding: 7px 10px; border-radius: 6px; background: var(--surface-muted); }
.release-stage { font-weight: 800; color: var(--theme-primary) !important; }
.release-stage.is-rolled_back { color: var(--danger) !important; }
.release-metric-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.release-metric { min-height: 102px; display: grid; align-content: center; gap: 4px; padding: 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); }
.release-metric span, .release-metric small { color: var(--text-muted); }
.release-metric strong { font-size: 22px; color: var(--text-primary); }
.release-alert-list, .release-review-list { display: grid; gap: 10px; }
.release-alert { display: flex; gap: 10px; padding: 12px 14px; border: 1px solid var(--line); border-left: 4px solid var(--theme-primary); border-radius: 7px; background: var(--surface); }
.release-alert.is-warning { border-left-color: #d97706; }
.release-alert.is-error, .release-alert.is-critical { border-left-color: var(--danger); }
.release-alert div { display: grid; gap: 3px; }
.release-alert span { color: var(--text-muted); font-size: 13px; }
.release-review-section { display: grid; gap: 14px; padding-top: 4px; }
.release-review-title b { min-width: 52px; padding: 7px 10px; border-radius: 999px; background: var(--theme-primary-soft); color: var(--theme-primary); text-align: center; }
.release-review-row { padding: 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); }
.release-review-meta { display: grid; gap: 4px; }
.release-review-meta span, .release-review-meta small { color: var(--text-muted); }
.release-review-blind { font-weight: 700; }
.release-source-link { width: fit-content; min-height: 44px; display: inline-flex; align-items: center; gap: 5px; margin-top: 3px; color: var(--theme-primary); font-size: 13px; font-weight: 700; text-decoration: none; }
.release-source-link:hover, .release-source-link:focus-visible { text-decoration: underline; outline: none; }
.release-review-conflict { color: var(--danger) !important; font-weight: 700; }
.release-review-actions { display: flex; gap: 8px; }
.release-review-actions button { min-height: 44px; border-radius: 7px; padding: 0 13px; font-weight: 700; }
.release-review-actions .review-decision { border: 1px solid var(--line); background: var(--surface); color: var(--text-primary); }
.release-review-actions .review-decision:hover, .release-review-actions .review-decision:focus-visible { border-color: var(--theme-primary); color: var(--theme-primary); outline: none; }
.release-review-actions button:disabled, .release-refresh:disabled { cursor: not-allowed; opacity: .5; }
.release-review-empty, .release-state-note { display: flex; align-items: center; gap: 9px; padding: 14px; border-radius: 8px; background: var(--surface-muted); color: var(--text-muted); }
.release-state-note.error { color: var(--danger); background: rgba(220, 38, 38, .07); }
@keyframes spin { to { transform: rotate(360deg); } }
@media (max-width: 960px) { .release-metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .release-monitor-head, .release-review-title, .release-review-row { flex-direction: column; }
  .release-metric-grid { grid-template-columns: 1fr; }
  .release-review-actions { width: 100%; }
  .release-review-actions button { flex: 1; }
}
</style>
