<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'

import { getWorkbenchOverview } from '@/api/workbench/home'
import type { WorkbenchCampus, WorkbenchOverviewResponse } from '@/api/workbench/types'
import { useAppStore } from '@/stores/app'

import DocumentRankingPanel from './components/DocumentRankingPanel.vue'
import HomeMetricCard from './components/HomeMetricCard.vue'
import SigningTrendPanel from './components/SigningTrendPanel.vue'
import TodoPanel from './components/TodoPanel.vue'
import type {
  HomeDocumentRanking,
  HomeMetricCard as HomeMetricCardData,
  HomeMetricKey,
  HomeRankingPeriod,
  HomeTodoItem,
  HomeTrendPoint,
} from './types'

const router = useRouter()
const appStore = useAppStore()

const loading = ref(true)
const loadFailed = ref(false)
const overview = ref<WorkbenchOverviewResponse | null>(null)
const rankingPeriod = ref<HomeRankingPeriod>(14)
let overviewRequestId = 0

const selectedCampus = computed<WorkbenchCampus>(() => appStore.selectedCampus)

const metrics = computed<HomeMetricCardData[]>(() => {
  const summary = overview.value?.summary
  const signedChange = summary?.todaySignedChange ?? 0
  const signedChangeTone: HomeMetricCardData['detailTone'] =
    signedChange > 0 ? 'up' : signedChange < 0 ? 'down' : 'muted'
  const signedChangeDetail =
    signedChange > 0
      ? `▲ 较昨日 +${signedChange} · 点击查看`
      : signedChange < 0
        ? `▼ 较昨日 ${signedChange} · 点击查看`
        : '较昨日持平 · 点击查看'

  return [
    {
      key: 'todaySigned',
      label: '今日已签署（单）',
      value: summary?.todaySigned ?? 0,
      tone: 'success',
      detail: signedChangeDetail,
      detailTone: signedChangeTone,
    },
    {
      key: 'pending',
      label: '待患者签署',
      value: summary?.pendingPatientSigning ?? 0,
      tone: 'brand',
      detail: '含手写板 / 短信 · 点击查看',
      detailTone: 'muted',
    },
    {
      key: 'overdue',
      label: '今日已超时',
      value: summary?.todayOverdue ?? 0,
      tone: 'danger',
      detail: '需重新发起 · 点击查看',
      detailTone: 'down',
    },
    {
      key: 'templates',
      label: '可用文档模板（份）',
      value: summary?.availableTemplates ?? 0,
      tone: 'brand',
      detail: `覆盖 ${summary?.coveredDepartments ?? 0} 个科室 · 点击查看`,
      detailTone: 'muted',
    },
  ]
})

const trendPoints = computed<HomeTrendPoint[]>(() => overview.value?.trend ?? [])
const todoItems = computed<HomeTodoItem[]>(() => overview.value?.todos ?? [])
const rankingRows = computed<HomeDocumentRanking[]>(() => overview.value?.documentRanking ?? [])

async function loadOverview() {
  const requestId = ++overviewRequestId
  loading.value = true
  loadFailed.value = false

  try {
    const nextOverview = await getWorkbenchOverview({
      campus: selectedCampus.value,
      rankingPeriod: rankingPeriod.value,
    })
    if (requestId !== overviewRequestId) {
      return
    }

    overview.value = nextOverview
  } catch {
    if (requestId !== overviewRequestId) {
      return
    }

    overview.value = null
    loadFailed.value = true
    ElMessage.error('首页数据加载失败，请稍后重试')
  } finally {
    if (requestId === overviewRequestId) {
      loading.value = false
    }
  }
}

function goToSigning(query: Record<string, string> = {}) {
  void router.push({
    name: 'workbench-signing',
    query: {
      campus: selectedCampus.value,
      ...query,
    },
  })
}

function handleMetricClick(key: HomeMetricKey) {
  if (key === 'templates') {
    void router.push({ name: 'management-documents' })
    return
  }

  const statusMap: Record<Exclude<HomeMetricKey, 'templates'>, string> = {
    todaySigned: 'signed',
    pending: 'pending',
    overdue: 'expired',
  }

  goToSigning({ status: statusMap[key], range: 'today' })
}

function handleTodoSelect(item: HomeTodoItem) {
  goToSigning({ taskId: item.id })
}

function handlePeriodChange(period: HomeRankingPeriod) {
  rankingPeriod.value = period
}

function retryLoad() {
  void loadOverview()
}

watch([selectedCampus, rankingPeriod], () => {
  void loadOverview()
})

onMounted(() => {
  void loadOverview()
})
</script>

<template>
  <section class="home-page">
    <div v-if="loading" class="home-loading" aria-label="正在加载首页">
      <div class="metric-loading-grid">
        <span v-for="index in 4" :key="index" />
      </div>
      <div class="panel-loading-grid">
        <span />
        <span />
      </div>
      <span class="ranking-loading" />
    </div>

    <div v-else-if="loadFailed" class="home-error">
      <div class="error-icon" aria-hidden="true">!</div>
      <p>首页数据暂时无法加载</p>
      <button type="button" class="retry-button" @click="retryLoad">重新加载</button>
    </div>

    <template v-else>
      <div class="metric-grid">
        <HomeMetricCard
          v-for="metric in metrics"
          :key="metric.key"
          :metric="metric"
          @click="handleMetricClick"
        />
      </div>

      <div class="overview-grid">
        <SigningTrendPanel :points="trendPoints" />
        <TodoPanel :items="todoItems" @select="handleTodoSelect" @view-all="goToSigning()" />
      </div>

      <DocumentRankingPanel
        :rows="rankingRows"
        :period="rankingPeriod"
        @update:period="handlePeriodChange"
        @manage="router.push({ name: 'management-documents' })"
      />
    </template>
  </section>
</template>

<style scoped>
.home-page {
  width: 100%;
  max-width: 1440px;
  margin: 0 auto;
}

.metric-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.overview-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(320px, 1fr);
  gap: 16px;
  margin-top: 16px;
}

.overview-grid > * {
  min-width: 0;
}

.ranking-panel {
  margin-top: 16px;
}

.home-loading {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.metric-loading-grid,
.panel-loading-grid {
  display: grid;
  gap: 16px;
}

.metric-loading-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.panel-loading-grid {
  grid-template-columns: minmax(0, 1.6fr) minmax(320px, 1fr);
}

.metric-loading-grid span,
.panel-loading-grid span,
.ranking-loading {
  display: block;
  min-height: 82px;
  background: linear-gradient(90deg, #edf3f5 25%, #f7fafb 37%, #edf3f5 63%);
  background-size: 400% 100%;
  border-radius: var(--r);
  box-shadow: var(--sh);
  animation: skeleton-shimmer 1.4s ease infinite;
}

.panel-loading-grid span {
  min-height: 274px;
}

.ranking-loading {
  min-height: 286px;
}

.home-error {
  display: flex;
  min-height: 380px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  color: var(--mut);
  text-align: center;
  background: var(--card);
  border-radius: var(--r);
  box-shadow: var(--sh);
}

.error-icon {
  display: grid;
  width: 46px;
  height: 46px;
  margin-bottom: 12px;
  color: var(--err);
  font-size: 24px;
  font-weight: 700;
  place-items: center;
  background: var(--err-l);
  border-radius: 50%;
}

.home-error p {
  margin: 0;
  font-size: 13px;
}

.retry-button {
  margin-top: 14px;
  padding: 7px 16px;
  color: var(--brand);
  font-size: 12px;
  background: #fff;
  border: 1px solid var(--brand);
  border-radius: 6px;
}

.retry-button:hover {
  background: var(--brand-l);
}

@keyframes skeleton-shimmer {
  0% {
    background-position: 100% 0;
  }

  100% {
    background-position: -100% 0;
  }
}

@media (max-width: 1200px) {
  .metric-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .overview-grid,
  .panel-loading-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 680px) {
  .metric-grid,
  .metric-loading-grid {
    grid-template-columns: 1fr;
  }
}
</style>
