<template>
  <div class="page-shell prediction">
    <section class="page-hero prediction-hero">
      <div class="page-eyebrow">Prediction</div>
      <h1 class="page-title">核心因子驱动的缺勤预测</h1>
      <p class="page-description">
        仅保留对结果最关键的输入项，让演示流程更聚焦，也让答辩老师更容易理解模型的业务逻辑。
      </p>
    </section>

    <el-row :gutter="20">
      <el-col :xs="24" :xl="15">
        <div class="prediction-input-grid">
          <el-card class="panel-card intro-card" shadow="never">
            <div class="section-heading" style="margin-bottom: 0">
              <div>
                <h3 class="section-title">中国企业缺勤风险输入</h3>
                <p class="section-caption">使用卡片分区组织核心因子，演示时更清晰。</p>
              </div>
              <el-button size="small" @click="resetForm">重置</el-button>
            </div>
            <div class="form-tip">
              系统会自动补齐企业背景、健康生活与组织属性等次级信息，页面仅保留对预测结果影响最大的核心字段。
            </div>
          </el-card>

          <el-card class="panel-card factor-card" shadow="never">
            <div class="section-heading">
              <div>
                <h3 class="section-title">缺勤事件核心信息</h3>
                <p class="section-caption">决定本次缺勤时长的直接事件属性。</p>
              </div>
              <span class="soft-tag">Event</span>
            </div>
            <el-form :model="form" label-width="118px" size="small">
              <el-row :gutter="18">
                <el-col :span="12">
                <el-form-item label="请假类型">
                  <el-select v-model="form.leave_type" style="width: 100%">
                    <el-option v-for="item in leaveTypes" :key="item" :label="item" :value="item" />
                  </el-select>
                </el-form-item>
              </el-col>
                <el-col :span="12">
                <el-form-item label="原因大类">
                  <el-select v-model="form.leave_reason_category" style="width: 100%">
                    <el-option v-for="item in leaveReasons" :key="item" :label="item" :value="item" />
                  </el-select>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="缺勤月份">
                  <el-select v-model="form.absence_month" style="width: 100%">
                    <el-option v-for="month in 12" :key="month" :label="`${month}月`" :value="month" />
                  </el-select>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="星期">
                  <el-select v-model="form.weekday" style="width: 100%">
                    <el-option v-for="item in weekdays" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="节假日前后">
                  <el-radio-group v-model="form.near_holiday_flag">
                    <el-radio :value="1">是</el-radio>
                    <el-radio :value="0">否</el-radio>
                  </el-radio-group>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="医院证明">
                  <el-radio-group v-model="form.medical_certificate_flag">
                    <el-radio :value="1">有</el-radio>
                    <el-radio :value="0">无</el-radio>
                  </el-radio-group>
                </el-form-item>
                </el-col>
              </el-row>
            </el-form>
          </el-card>

          <el-card class="panel-card factor-card" shadow="never">
            <div class="section-heading">
              <div>
                <h3 class="section-title">工作压力与排班</h3>
                <p class="section-caption">体现通勤、加班和排班对缺勤的影响。</p>
              </div>
              <span class="soft-tag">Workload</span>
            </div>
            <el-form :model="form" label-width="118px" size="small">
              <el-row :gutter="18">
                <el-col :span="12">
                <el-form-item label="班次类型">
                  <el-select v-model="form.shift_type" style="width: 100%">
                    <el-option v-for="item in shiftTypes" :key="item" :label="item" :value="item" />
                  </el-select>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="夜班岗位">
                  <el-radio-group v-model="form.is_night_shift">
                    <el-radio :value="1">是</el-radio>
                    <el-radio :value="0">否</el-radio>
                  </el-radio-group>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="月均加班时长">
                  <el-input-number v-model="form.monthly_overtime_hours" :min="0" :max="100" style="width: 100%" />
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="通勤时长(分钟)">
                  <el-input-number v-model="form.commute_minutes" :min="5" :max="150" style="width: 100%" />
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="慢性病史">
                  <el-radio-group v-model="form.chronic_disease_flag">
                    <el-radio :value="1">有</el-radio>
                    <el-radio :value="0">无</el-radio>
                  </el-radio-group>
                </el-form-item>
                </el-col>
              </el-row>
            </el-form>
          </el-card>

          <el-card class="panel-card factor-card" shadow="never">
            <div class="section-heading">
              <div>
                <h3 class="section-title">家庭与补充因素</h3>
                <p class="section-caption">作为结果修正项，为预测增加业务语境。</p>
              </div>
              <span class="soft-tag">Context</span>
            </div>
            <el-form :model="form" label-width="118px" size="small">
              <el-row :gutter="18">
                <el-col :span="12">
                <el-form-item label="子女数量">
                  <el-input-number v-model="form.children_count" :min="0" :max="3" style="width: 100%" />
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="所属行业">
                  <el-select v-model="form.industry" style="width: 100%">
                    <el-option v-for="item in industries" :key="item" :label="item" :value="item" />
                  </el-select>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="婚姻状态">
                  <el-select v-model="form.marital_status" style="width: 100%">
                    <el-option v-for="item in maritalStatuses" :key="item" :label="item" :value="item" />
                  </el-select>
                </el-form-item>
                </el-col>
              </el-row>
            </el-form>
          </el-card>

          <el-card class="panel-card factor-card action-card" shadow="never">
            <div class="section-heading">
              <div>
                <h3 class="section-title">预测设置</h3>
                <p class="section-caption">支持自动选择最优模型或查看模型对比。</p>
              </div>
              <span class="soft-tag">Action</span>
            </div>
            <el-form :model="form" label-width="118px" size="small">
              <el-row :gutter="18">
                <el-col :span="12">
                <el-form-item label="选择模型">
                  <el-select v-model="selectedModel" style="width: 100%" :loading="modelsLoading">
                    <el-option label="自动选择最优" value="" />
                    <el-option v-for="model in availableModels" :key="model.name" :label="model.name_cn" :value="model.name">
                      <span>{{ model.name_cn }}</span>
                      <span style="float: right; color: #909399; font-size: 12px">R²: {{ model.metrics?.r2?.toFixed(2) || '-' }}</span>
                    </el-option>
                  </el-select>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="模型对比">
                  <el-switch v-model="showCompare" active-text="显示" inactive-text="隐藏" />
                </el-form-item>
                </el-col>
              </el-row>

              <div class="action-row">
                <el-button type="primary" @click="handlePredict" :loading="loading">开始预测</el-button>
                <el-button @click="handleCompare" :loading="compareLoading">模型对比</el-button>
              </div>
            </el-form>
          </el-card>
        </div>
      </el-col>
      <el-col :xs="24" :xl="9">
        <el-card class="panel-card result-card merged-result-card" shadow="never">
          <template #header>
            <div class="section-heading" style="margin-bottom: 0">
              <div>
                <h3 class="section-title">预测结果与风险说明</h3>
                <p class="section-caption">在同一张卡片内查看预测值、模型信息和风险区间说明。</p>
              </div>
              <span class="soft-tag">Result</span>
            </div>
          </template>
          <div class="merged-result-grid">
            <div>
              <div v-if="result" class="result-container">
                <div class="result-stack">
                  <div class="result-info-card result-info-primary">
                    <div class="mini-label">预测缺勤时长</div>
                    <div class="result-value">{{ result.predicted_hours }}</div>
                    <div class="result-unit">小时</div>
                  </div>

                  <div class="result-info-card">
                    <div class="mini-label">风险等级</div>
                    <el-tag :type="riskTagType" size="large">{{ result.risk_label }}</el-tag>
                  </div>

                  <div class="result-info-card">
                    <div class="mini-label">使用模型</div>
                    <div class="mini-value">{{ result.model_name_cn }}</div>
                  </div>

                  <div class="result-info-card">
                    <div class="mini-label">置信度</div>
                    <div class="mini-value">{{ (result.confidence * 100).toFixed(0) }}%</div>
                  </div>
                </div>
              </div>
              <el-empty v-else description="输入中国企业员工场景后开始预测" />
            </div>

            <div class="risk-legend-cards">
              <div class="risk-level-card risk-level-low">
                <div class="risk-card-head">
                  <el-tag type="success" size="small">低风险</el-tag>
                </div>
                <div class="risk-card-rule">缺勤时长 &lt; 4 小时</div>
                <div class="risk-card-desc">通常为短时请假或轻度波动。</div>
              </div>

              <div class="risk-level-card risk-level-medium">
                <div class="risk-card-head">
                  <el-tag type="warning" size="small">中风险</el-tag>
                </div>
                <div class="risk-card-rule">缺勤时长 4 - 8 小时</div>
                <div class="risk-card-desc">属于需要关注的常规风险区间。</div>
              </div>

              <div class="risk-level-card risk-level-high">
                <div class="risk-card-head">
                  <el-tag type="danger" size="small">高风险</el-tag>
                </div>
                <div class="risk-card-rule">缺勤时长 &gt; 8 小时</div>
                <div class="risk-card-desc">通常对应较强事件驱动或持续性风险。</div>
              </div>
            </div>
          </div>
        </el-card>

        <el-card v-if="compareResults.length > 0" class="panel-card compare-card" shadow="never">
          <template #header>
            <div class="section-heading" style="margin-bottom: 0">
              <div>
                <h3 class="section-title">模型对比结果</h3>
                <p class="section-caption">选择最适合展示的候选模型。</p>
              </div>
              <span class="soft-tag">Compare</span>
            </div>
          </template>
          <el-table :data="compareResults" size="small" :row-class-name="getRowClass">
            <el-table-column prop="model_name_cn" label="模型" width="100" />
            <el-table-column prop="predicted_hours" label="预测时长" width="90">
              <template #default="{ row }">{{ row.predicted_hours }}h</template>
            </el-table-column>
            <el-table-column prop="risk_label" label="风险等级" width="80">
              <template #default="{ row }">
                <el-tag :type="getRiskType(row.risk_level)" size="small">{{ row.risk_label }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="r2" label="R²" width="70">
              <template #default="{ row }">{{ row.r2?.toFixed(3) }}</template>
            </el-table-column>
            <el-table-column label="推荐" width="60">
              <template #default="{ row }">
                <el-tag v-if="row.recommended" type="success" size="small">推荐</el-tag>
              </template>
            </el-table-column>
          </el-table>
        </el-card>

        <el-card v-if="shapLocalData" class="panel-card shap-card" shadow="never">
          <template #header>
            <div class="section-heading" style="margin-bottom: 0">
              <div>
                <h3 class="section-title">SHAP 预测解释</h3>
                <p class="section-caption">每个特征对本次预测的贡献度（红色推高/蓝色拉低）</p>
              </div>
              <span class="soft-tag">Explain</span>
            </div>
          </template>
          <div class="shap-dimension-badges">
            <span v-for="(val, dim) in shapLocalData.dimension_contribution" :key="dim"
              class="shap-badge" :class="val >= 0 ? 'shap-badge-positive' : 'shap-badge-negative'">
              {{ dim }}: {{ val >= 0 ? '+' : '' }}{{ val }}
            </span>
          </div>
          <div ref="shapForceRef" style="height: 320px"></div>
        </el-card>

      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { computed, nextTick, onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import * as echarts from 'echarts'
import request from '@/api/request'
import { getLocalExplanation } from '@/api/shap'

const industries = ['制造业', '互联网', '零售连锁', '物流运输', '金融服务', '医药健康', '建筑工程']
const shiftTypes = ['标准白班', '两班倒', '三班倒', '弹性班']
const maritalStatuses = ['未婚', '已婚', '离异/其他']
const leaveTypes = ['病假', '事假', '年假', '调休', '婚假', '丧假', '产检育儿假', '工伤假', '其他']
const leaveReasons = ['身体不适', '家庭事务', '子女照护', '交通受阻', '突发事件', '职业疲劳', '就医复查']
const weekdays = [
  { label: '周一', value: 1 },
  { label: '周二', value: 2 },
  { label: '周三', value: 3 },
  { label: '周四', value: 4 },
  { label: '周五', value: 5 },
  { label: '周六', value: 6 },
  { label: '周日', value: 7 }
]

const defaultForm = {
  industry: '制造业',
  shift_type: '标准白班',
  marital_status: '已婚',
  children_count: 1,
  monthly_overtime_hours: 26,
  commute_minutes: 42,
  is_night_shift: 0,
  chronic_disease_flag: 0,
  absence_month: 5,
  weekday: 2,
  leave_type: '病假',
  leave_reason_category: '身体不适',
  near_holiday_flag: 0,
  medical_certificate_flag: 1
}

const form = ref({ ...defaultForm })
const result = ref(null)
const loading = ref(false)
const compareLoading = ref(false)
const compareResults = ref([])
const showCompare = ref(false)
const selectedModel = ref('')
const availableModels = ref([])
const modelsLoading = ref(false)
const shapLocalData = ref(null)
const shapForceRef = ref(null)

const riskTagType = computed(() => {
  if (!result.value) return 'info'
  return getRiskType(result.value.risk_level)
})

function getRiskType(level) {
  return level === 'low' ? 'success' : level === 'medium' ? 'warning' : 'danger'
}

function getRowClass({ row }) {
  return row.recommended ? 'recommended-row' : ''
}

function resetForm() {
  form.value = { ...defaultForm }
  result.value = null
  compareResults.value = []
  shapLocalData.value = null
}

async function loadModels() {
  modelsLoading.value = true
  try {
    const res = await request.get('/predict/models')
    availableModels.value = res.models || []
  } finally {
    modelsLoading.value = false
  }
}

async function handlePredict() {
  loading.value = true
  try {
    const params = { ...form.value }
    if (selectedModel.value) params.model_type = selectedModel.value
    result.value = await request.post('/predict/single', params)
    if (showCompare.value) await handleCompare()
    // 加载 SHAP 局部解释
    loadShapLocal(params)
  } catch (e) {
    ElMessage.error(`预测失败: ${e.message}`)
  } finally {
    loading.value = false
  }
}

async function loadShapLocal(params) {
  try {
    const modelType = params.model_type || ''
    const data = await getLocalExplanation({ ...params, model_type: modelType })
    if (data && !data.error) {
      shapLocalData.value = data
      requestAnimationFrame(() => {
        nextTick().then(renderShapForce)
      })
    }
  } catch (e) { /* ignore */ }
}

function renderShapForce() {
  const el = shapForceRef.value
  if (!el || !shapLocalData.value?.features) { console.warn('shapForce: DOM or data missing'); return }
  let chart = echarts.getInstanceByDom(el)
  if (!chart) chart = echarts.init(el)

  const features = shapLocalData.value.features.slice(0, 12)
  const sorted = [...features].sort((a, b) => b.shap_value - a.shap_value)

  chart.setOption({
    tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
    grid: { left: 120, right: 30, top: 10, bottom: 30 },
    xAxis: { type: 'value', name: 'SHAP值' },
    yAxis: { type: 'category', data: sorted.map(f => f.name_cn) },
    series: [{
      type: 'bar', data: sorted.map(f => ({
        value: f.shap_value,
        itemStyle: { color: f.shap_value >= 0 ? '#ef4444' : '#3b82f6' },
      })),
    }],
  })
}

async function handleCompare() {
  compareLoading.value = true
  try {
    const res = await request.post('/predict/compare', form.value)
    compareResults.value = res.results || []
  } catch (e) {
    ElMessage.error(`对比失败: ${e.message}`)
  } finally {
    compareLoading.value = false
  }
}

onMounted(() => {
  loadModels()
})
</script>

<style scoped>
.result-container {
  display: block;
  padding: 8px 0 4px;
}

.prediction-hero {
  background:
    linear-gradient(135deg, rgba(15, 23, 42, 0.96), rgba(15, 118, 110, 0.92) 50%, rgba(194, 65, 12, 0.88));
}

.prediction-input-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

.intro-card {
  grid-column: 1 / -1;
}

.action-card {
  grid-column: 1 / -1;
}

.result-card,
.compare-card {
  height: 100%;
}

.compare-card {
  margin-top: 20px;
}

.merged-result-card {
  min-height: 100%;
}

.merged-result-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-items: start;
}

.result-stack {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.result-info-card {
  padding: 18px 14px;
  border: 1px solid var(--line-soft);
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.76);
  text-align: center;
}

.result-info-primary {
  grid-column: 1 / -1;
  padding: 24px 18px;
  border: 1px solid rgba(15, 118, 110, 0.14);
  background: linear-gradient(135deg, rgba(15, 118, 110, 0.12), rgba(58, 122, 254, 0.08));
}

.mini-label {
  margin-bottom: 10px;
  font-size: 12px;
  color: var(--text-subtle);
}

.mini-value {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-main);
}

.form-tip {
  margin-top: 14px;
  padding: 12px 14px;
  font-size: 13px;
  line-height: 1.6;
  color: #606266;
  background: #f4f8ff;
  border-left: 3px solid #3A7AFE;
  border-radius: 6px;
}

.factor-card :deep(.el-form-item) {
  margin-bottom: 18px;
}

.action-row {
  display: flex;
  gap: 12px;
  margin-top: 14px;
}

.result-value {
  font-size: 48px;
  font-weight: bold;
  color: #3A7AFE;
}

.result-unit {
  margin-top: 8px;
  font-size: 14px;
  color: #909399;
}

.risk-legend-cards {
  display: grid;
  gap: 12px;
}

.risk-level-card {
  padding: 16px;
  border-radius: 18px;
  border: 1px solid var(--line-soft);
  background: rgba(255, 255, 255, 0.76);
}

.risk-level-low {
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.08), rgba(255, 255, 255, 0.9));
}

.risk-level-medium {
  background: linear-gradient(135deg, rgba(245, 158, 11, 0.1), rgba(255, 255, 255, 0.9));
}

.risk-level-high {
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(255, 255, 255, 0.9));
}

.risk-card-head {
  margin-bottom: 10px;
}

.risk-card-rule {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
}

.risk-card-desc {
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-subtle);
}

.el-divider {
  margin: 15px 0;
}

:deep(.recommended-row) {
  background-color: #f0f9eb;
}

:deep(.intro-card .el-card__header),
:deep(.result-card .el-card__header),
:deep(.compare-card .el-card__header) {
  padding-bottom: 0;
  border-bottom: none;
}

:deep(.factor-card .el-card__header) {
  border-bottom: none;
  padding-bottom: 0;
}

@media (max-width: 1200px) {
  .prediction-input-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 768px) {
  .merged-result-grid,
  .result-stack {
    grid-template-columns: 1fr;
  }
}

.shap-card {
  margin-top: 20px;
}

.shap-dimension-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.shap-badge {
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}

.shap-badge-positive {
  background: rgba(239, 68, 68, 0.1);
  color: #ef4444;
  border: 1px solid rgba(239, 68, 68, 0.2);
}

.shap-badge-negative {
  background: rgba(59, 130, 246, 0.1);
  color: #3b82f6;
  border: 1px solid rgba(59, 130, 246, 0.2);
}
</style>
