<template>
  <section class="cfo-value-dashboard" aria-labelledby="cfo-value-title">
    <header class="panel value-dashboard-header">
      <div>
        <span class="value-eyebrow">Evidence-backed value</span>
        <h2 id="cfo-value-title">经营价值与节省闭环</h2>
        <p>只把有基线、证据、canonical 去重和独立财务确认的实际结果计入现金节省。</p>
      </div>
      <div class="value-source-summary">
        <span :class="['value-source-status', dashboardState]">
          <i class="mdi mdi-database-check-outline" aria-hidden="true"></i>
          {{ sourceStatusLabel }}
        </span>
        <small>{{ windowLabel }}</small>
        <small>{{ freshnessLabel }}</small>
        <button type="button" class="btn" :disabled="dashboardLoading" @click="reloadAll">
          <i :class="dashboardLoading ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-refresh'" aria-hidden="true"></i>
          {{ dashboardLoading ? '同步中' : '刷新' }}
        </button>
      </div>
    </header>

    <section class="panel value-filter-panel" aria-labelledby="value-filter-title">
      <div class="value-filter-head">
        <div>
          <h3 id="value-filter-title">筛选经营价值</h3>
          <p>筛选条件会写入当前 URL，刷新和返回后仍可恢复。</p>
        </div>
        <button
          type="button"
          class="value-filter-toggle"
          :aria-expanded="advancedFiltersOpen ? 'true' : 'false'"
          aria-controls="value-advanced-filters"
          @click="advancedFiltersOpen = !advancedFiltersOpen"
        >
          <i class="mdi mdi-tune-variant" aria-hidden="true"></i>
          高级筛选
          <span v-if="activeFilterCount">{{ activeFilterCount }}</span>
        </button>
      </div>
      <form class="value-filter-form" @submit.prevent="applyFilters">
        <div class="value-filter-primary">
          <label>
            <span>价值类型</span>
            <select v-model="filterDraft.valueKind">
              <option value="">全部类型</option>
              <option value="cash">现金节省</option>
              <option value="labor">工时价值</option>
            </select>
          </label>
          <label>
            <span>机会状态 <em>仅筛选下方台账</em></span>
            <select v-model="filterDraft.status">
              <option value="">全部状态</option>
              <option v-for="option in statusOptions" :key="option.value" :value="option.value">{{ option.label }}</option>
            </select>
          </label>
          <label>
            <span>来源类型</span>
            <input v-model.trim="filterDraft.sourceType" maxlength="50" placeholder="例如 standard_adjustment" autocomplete="off" />
          </label>
          <label>
            <span>负责人 ID</span>
            <input v-model.trim="filterDraft.ownerId" maxlength="120" placeholder="输入负责人 ID" autocomplete="off" />
          </label>
        </div>
        <div v-if="advancedFiltersOpen" id="value-advanced-filters" class="value-filter-advanced">
          <label><span>部门 ID</span><input v-model.trim="filterDraft.departmentId" maxlength="160" autocomplete="off" /></label>
          <label><span>项目编码</span><input v-model.trim="filterDraft.projectCode" maxlength="160" autocomplete="off" /></label>
          <label><span>费用类型</span><input v-model.trim="filterDraft.expenseType" maxlength="80" autocomplete="off" /></label>
          <label><span>供应商 ID</span><input v-model.trim="filterDraft.supplierId" maxlength="160" autocomplete="off" /></label>
          <label><span>城市</span><input v-model.trim="filterDraft.city" maxlength="160" autocomplete="off" /></label>
        </div>
        <div class="value-filter-actions">
          <button type="button" class="btn ghost" :disabled="dashboardLoading" @click="resetFilters">重置</button>
          <button type="submit" class="btn primary" :disabled="dashboardLoading">
            <i class="mdi mdi-filter-check-outline" aria-hidden="true"></i>
            应用筛选
          </button>
        </div>
      </form>
    </section>

    <div v-if="mutationMessage" class="value-feedback success" role="status" aria-live="polite">
      <i class="mdi mdi-check-circle-outline" aria-hidden="true"></i>
      {{ mutationMessage }}
    </div>

    <div v-if="dashboardState === 'loading'" class="panel value-page-state loading" role="status" aria-live="polite">
      <i class="mdi mdi-loading mdi-spin" aria-hidden="true"></i>
      <strong>正在核对价值台账与财务确认记录</strong>
      <span>加载期间不会展示旧的演示数字。</span>
    </div>
    <div v-else-if="dashboardState === 'permission'" class="panel value-page-state permission" role="alert">
      <i class="mdi mdi-shield-lock-outline" aria-hidden="true"></i>
      <strong>当前账号无权查看企业经营价值</strong>
      <span>{{ dashboardError?.message || '该看板仅向财务、管理层和授权平台管理员开放。' }}</span>
    </div>
    <div v-else-if="dashboardState === 'error'" class="panel value-page-state error" role="alert">
      <i class="mdi mdi-alert-circle-outline" aria-hidden="true"></i>
      <strong>经营价值数据加载失败</strong>
      <span>{{ dashboardError?.message || '请检查网络后重试。' }}</span>
      <button type="button" class="btn" @click="reloadAll">重新加载</button>
    </div>
    <div v-else-if="dashboardState === 'empty'" class="panel value-page-state empty" role="status">
      <i class="mdi mdi-database-off-outline" aria-hidden="true"></i>
      <strong>当前范围还没有价值台账记录</strong>
      <span>这不是零节省；系统尚无可用于判断的机会或实际结果。可调整顶部时间范围或清空筛选。</span>
      <button v-if="activeFilterCount" type="button" class="btn" @click="resetFilters">清空筛选</button>
    </div>

    <template v-else>
      <div v-if="dashboardState === 'partial'" class="value-feedback warning" role="status">
        <i class="mdi mdi-alert-outline" aria-hidden="true"></i>
        当前结果为部分覆盖：存在证据、汇率或去重待补项，相关记录不会进入已核验主指标。
      </div>
      <div v-if="dashboardStale" class="value-feedback stale" role="status">
        <i class="mdi mdi-clock-alert-outline" aria-hidden="true"></i>
        数据源超过 24 小时未产生新事实；页面保留最后一次真实结果并明确标记为陈旧。
      </div>
      <div v-if="dashboardError" class="value-feedback error" role="alert">
        <i class="mdi mdi-cloud-alert-outline" aria-hidden="true"></i>
        最新同步失败，当前展示的是上一次成功读取的数据：{{ dashboardError.message }}
      </div>

      <div class="value-kpi-grid">
        <article v-for="kpi in kpis" :key="kpi.key" :class="['panel', 'value-kpi-card', kpi.state]">
          <div class="value-kpi-head">
            <span>{{ kpi.label }}</span>
            <em>{{ kpi.statusLabel }}</em>
          </div>
          <strong>{{ kpi.displayValue }}</strong>
          <p>{{ kpi.detail }}</p>
          <details v-if="kpi.requiredInputs?.length || kpi.definition">
            <summary>{{ kpi.requiredInputs?.length ? '查看缺失输入' : '查看口径' }}</summary>
            <ul v-if="kpi.requiredInputs?.length">
              <li v-for="item in kpi.requiredInputs" :key="item">{{ item }}</li>
            </ul>
            <p v-else>{{ kpi.definition }}</p>
          </details>
        </article>
      </div>

      <section class="value-dashboard-grid">
        <article class="panel value-dashboard-card value-funnel-card">
          <div class="value-card-head">
            <div><h3>价值转化漏斗</h3><p>预计、执行、实际、确认与冲回严格分层。</p></div>
          </div>
          <ol class="value-funnel-list">
            <li v-for="stage in funnelRows" :key="stage.key">
              <div><span>{{ stage.label }}</span><strong>{{ stage.count }} 项</strong></div>
              <i aria-hidden="true"><b :style="{ width: stage.width }"></b></i>
              <small>{{ stage.valueLabel }}</small>
            </li>
          </ol>
          <div v-if="realizationRates.length" class="value-realization-rates">
            <span v-for="item in realizationRates" :key="item.currency">
              {{ item.currency }} 成熟机会实现率 <strong>{{ item.label }}</strong>
            </span>
          </div>
        </article>

        <article class="panel value-dashboard-card value-trend-card">
          <div class="value-card-head">
            <div><h3>实际价值趋势</h3><p>按实际发生月份和币种展示，不跨币种相加。</p></div>
            <label v-if="trend.currencies.length > 1" class="value-compact-select">
              <span>币种</span>
              <select v-model="trendCurrency">
                <option v-for="currency in trend.currencies" :key="currency" :value="currency">{{ currency }}</option>
              </select>
            </label>
          </div>
          <CfoValueTrendChart :rows="trend.rows" :currency="trend.selectedCurrency" />
        </article>

        <article class="panel value-dashboard-card value-breakdown-card">
          <div class="value-card-head">
            <div><h3>价值归因分解</h3><p>按业务维度钻取预计价值与财务确认价值。</p></div>
          </div>
          <div class="value-dimension-tabs" role="group" aria-label="价值分解维度">
            <button
              v-for="group in breakdownGroups"
              :key="group.dimension"
              type="button"
              :aria-pressed="activeBreakdown.dimension === group.dimension ? 'true' : 'false'"
              :class="{ active: activeBreakdown.dimension === group.dimension }"
              @click="activeBreakdownDimension = group.dimension"
            >{{ group.label }}</button>
          </div>
          <div v-if="activeBreakdown.items.length" class="value-breakdown-list">
            <div v-for="item in activeBreakdown.items" :key="item.rowKey" class="value-breakdown-row">
              <div><strong>{{ item.dimensionName }}</strong><span>{{ item.opportunityCount }} 个机会 · {{ item.currency || '无币种' }}</span></div>
              <i aria-hidden="true"><b :style="{ width: item.width }"></b></i>
              <div><strong>{{ item.verifiedLabel }}</strong><span>预计 {{ item.estimatedLabel }}</span></div>
            </div>
          </div>
          <p v-else class="value-inline-state">该维度暂无可归因记录。</p>
        </article>

        <article class="panel value-dashboard-card value-guardrail-card">
          <div class="value-card-head">
            <div><h3>价值护栏</h3><p>避免误把风险暴露、重复记录或未确认结果算成节省。</p></div>
          </div>
          <div class="value-guardrail-list">
            <div v-for="item in guardrailRows" :key="item.key" :class="['value-guardrail-row', item.status]">
              <i :class="item.status === 'ok' ? 'mdi mdi-check-circle-outline' : (item.status === 'attention' ? 'mdi mdi-alert-outline' : 'mdi mdi-minus-circle-outline')" aria-hidden="true"></i>
              <div><strong>{{ item.label }}</strong><span>{{ item.reason || [item.countLabel, item.valueLabel, item.rateLabel].filter((value) => value && value !== '—').join(' · ') }}</span></div>
              <em>{{ item.statusLabel }}</em>
            </div>
          </div>
        </article>

        <article class="panel value-dashboard-card value-quality-card">
          <div class="value-card-head">
            <div><h3>数据质量与覆盖</h3><p>每个缺口都明确展示，不使用默认值掩盖。</p></div>
            <span class="value-source-chip">Savings Ledger {{ dashboard?.source?.ledgerRevision || '' }}</span>
          </div>
          <div class="value-quality-grid">
            <div v-for="item in dataQualityRows" :key="item.key" :class="item.tone">
              <strong>{{ item.displayValue }}</strong><span>{{ item.label }}</span>
            </div>
          </div>
          <ul v-if="qualityNotes.length || coverageNotes.length" class="value-coverage-notes">
            <li v-for="note in [...qualityNotes, ...coverageNotes]" :key="note">{{ note }}</li>
          </ul>
        </article>
      </section>

      <section class="panel value-opportunity-panel" aria-labelledby="value-opportunities-title">
        <div class="value-card-head">
          <div>
            <h3 id="value-opportunities-title">节省机会台账</h3>
            <p>共 {{ Number(opportunities.total || 0) }} 条；进入详情可查看基线、证据、实际结果和不可变事件。</p>
          </div>
          <span v-if="opportunitiesLoading" class="value-list-loading" role="status"><i class="mdi mdi-loading mdi-spin"></i>同步中</span>
        </div>
        <div v-if="opportunitiesLoading && !opportunities.generatedAt" class="value-list-state" role="status" aria-live="polite">
          <i class="mdi mdi-loading mdi-spin" aria-hidden="true"></i>
          <span>正在加载节省机会台账</span>
        </div>
        <div v-else-if="opportunitiesError" class="value-list-state error" role="alert">
          <span>{{ opportunitiesError.message || '机会台账加载失败。' }}</span>
          <button type="button" class="btn" @click="loadOpportunities">重试</button>
        </div>
        <div v-else-if="opportunityRows.length" class="value-opportunity-list">
          <article v-for="item in opportunityRows" :key="item.id" class="value-opportunity-row">
            <div class="value-opportunity-main">
              <span :class="['value-status-pill', item.statusMeta.tone]">{{ item.statusMeta.label }}</span>
              <div><strong>{{ item.title }}</strong><small>{{ item.claimNoSnapshot }} · {{ item.category }} · {{ item.sourceType }}</small></div>
            </div>
            <div class="value-opportunity-amount"><strong>{{ item.estimatedLabel }}</strong><span>预计净节省 · 置信度 {{ item.confidenceLabel }}</span></div>
            <div class="value-opportunity-owner"><strong>{{ item.ownerLabel }}</strong><span>更新 {{ item.updatedLabel }}</span></div>
            <button type="button" class="btn" @click="openOpportunity(item.id)">查看证据链</button>
          </article>
        </div>
        <div v-else class="value-list-state" role="status">当前筛选条件下暂无节省机会。</div>
        <el-pagination
          v-if="Number(opportunities.totalPages || 0) > 1"
          class="value-pagination"
          background
          layout="prev, pager, next"
          :current-page="page"
          :page-count="Number(opportunities.totalPages || 0)"
          @current-change="setPage"
        />
      </section>
    </template>

    <CfoValueOpportunityDrawer
      :open="detailOpen"
      :opportunity="selectedOpportunity"
      :loading="selectedOpportunityLoading"
      :error="selectedOpportunityError"
      @update:open="handleDetailOpenChange"
      @retry="openOpportunity(selectedOpportunityId)"
      @action="openActionDialog"
    />
    <CfoValueActionDialog
      v-model:open="actionDialogOpen"
      :action="actionContext.action"
      :target="actionContext.target"
      :opportunity="actionContext.opportunity"
      :submitting="mutationLoading"
      :error="mutationError"
      @submit="handleSubmitAction"
    />
  </section>
</template>

<script setup>
import { computed, reactive, ref } from 'vue'

import CfoValueTrendChart from '../charts/CfoValueTrendChart.vue'
import CfoValueActionDialog from './CfoValueActionDialog.vue'
import CfoValueOpportunityDrawer from './CfoValueOpportunityDrawer.vue'
import { useCfoValueDashboard } from '../../composables/useCfoValueDashboard.js'
import { formatDateTime, formatPercent } from '../../views/scripts/cfoValueDashboardModel.js'

const props = defineProps({
  activeRange: { type: String, default: '近10日' },
  customRange: { type: Object, default: () => ({ start: '', end: '' }) }
})

const advancedFiltersOpen = ref(false)
const actionDialogOpen = ref(false)
const actionContext = reactive({ action: '', target: null, opportunity: null })
const statusOptions = [
  ['identified', '待评估'], ['accepted', '已接受'], ['in_progress', '执行中'],
  ['realized', '实际待确认'], ['verified', '财务已确认'], ['reversed', '已冲回'],
  ['rejected', '已拒绝'], ['expired', '已到期']
].map(([value, label]) => ({ value, label }))

const {
  activeBreakdown,
  activeBreakdownDimension,
  breakdownGroups,
  dashboard,
  dashboardError,
  dashboardLoading,
  dashboardState,
  dashboardStale,
  dataQualityRows,
  detailOpen,
  filterDraft,
  funnelRows,
  guardrailRows,
  kpis,
  mutationError,
  mutationLoading,
  mutationMessage,
  opportunities,
  opportunitiesError,
  opportunitiesLoading,
  opportunityRows,
  page,
  selectedOpportunity,
  selectedOpportunityError,
  selectedOpportunityId,
  selectedOpportunityLoading,
  trend,
  trendCurrency,
  applyFilters,
  closeOpportunity,
  loadOpportunities,
  openOpportunity,
  reloadAll,
  resetFilters,
  setPage,
  submitAction
} = useCfoValueDashboard(props)

const activeFilterCount = computed(() => Object.values(filterDraft).filter((value) => String(value || '').trim()).length)
const coverageNotes = computed(() => dashboard.value?.source?.coverageNotes || [])
const qualityNotes = computed(() => dashboard.value?.dataQuality?.notes || [])
const windowLabel = computed(() => {
  const window = dashboard.value?.window
  if (!window) return `时间范围：${props.activeRange}`
  return `${new Date(window.start).toLocaleDateString('zh-CN')} - ${new Date(window.end).toLocaleDateString('zh-CN')}`
})
const freshnessLabel = computed(() => {
  const freshness = dashboard.value?.source?.freshnessAt
  return freshness ? `事实更新：${formatDateTime(freshness)}` : '事实更新：暂无记录'
})
const sourceStatusLabel = computed(() => ({
  loading: '正在核对', permission: '无访问权限', error: '读取失败', empty: '暂无事实',
  partial: '部分覆盖', stale: '数据陈旧', ready: '真实数据'
}[dashboardState.value] || '状态未知'))
const realizationRates = computed(() => Object.entries(dashboard.value?.funnel?.realizationRateByCurrency || {})
  .map(([currency, value]) => ({ currency, label: value === null ? '不可计算' : formatPercent(value) })))

function handleDetailOpenChange(open) {
  if (!open) closeOpportunity()
}

function openActionDialog(payload) {
  actionContext.action = payload.action
  actionContext.target = payload.target
  actionContext.opportunity = payload.opportunity
  mutationError.value = null
  actionDialogOpen.value = true
}

async function handleSubmitAction(command) {
  try {
    await submitAction(command)
    actionDialogOpen.value = false
  } catch {
    // 错误由对话框内的可访问错误区域展示，保留表单便于修正或重试。
  }
}
</script>

<style scoped src="../../assets/styles/components/cfo-value-dashboard.css"></style>
