<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import http, { apiErrorMessage } from '../api/http'

const route = useRoute()
const isMine = computed(() => route.meta.mine === true)
const isPublic = computed(() => route.meta.public === true)
const loading = ref(false)
const terms = ref<any[]>([])
const classes = ref<any[]>([])
const termId = ref('')
const classId = ref('')
const timetable = ref<any | null>(null)
const weekdays = ['', '周一', '周二', '周三', '周四', '周五', '周六', '周日']
const patternLabels: Record<string, string> = { All: '每周', Odd: '单周', Even: '双周' }

const maxPeriods = computed(() => {
  const slotMaximum = Math.max(0, ...((timetable.value?.slots ?? []).map((x: any) => x.periodNumber)))
  const entryMaximum = Math.max(
    0,
    ...((timetable.value?.entries ?? []).map((x: any) => x.startPeriod + x.periodCount - 1)),
  )
  return Math.max(8, slotMaximum, entryMaximum)
})

const slotMap = computed<Map<number, any>>(() =>
  new Map<number, any>(
    (timetable.value?.slots ?? []).map((item: any) => [item.periodNumber, item]),
  ),
)

function formatTime(value: string) {
  return value?.slice(0, 5) ?? ''
}

function entryStyle(entry: any) {
  return {
    gridColumn: String(entry.dayOfWeek + 1),
    gridRow: `${entry.startPeriod + 1} / span ${entry.periodCount}`,
  }
}

function weeks(entry: any) {
  const pattern = patternLabels[entry.weekPattern]
  return `${entry.startWeek}—${entry.endWeek}周${pattern === '每周' ? '' : ` · ${pattern}`}`
}

function location(entry: any) {
  return [entry.campusName, entry.buildingName, entry.classroomName].filter(Boolean).join(' · ')
}

async function loadOptions() {
  const { data } = await http.get('/timetables/options')
  terms.value = data.terms
  classes.value = data.classes
  termId.value = data.terms.find((item: any) => item.isCurrent)?.id
    ?? data.terms.find((item: any) => item.hasPublishedTimetable)?.id
    ?? data.terms[0]?.id
    ?? ''
  classId.value = data.classes.find((item: any) => item.hasPublishedTimetable)?.id
    ?? data.classes[0]?.id
    ?? ''
}

async function loadTimetable() {
  if (!termId.value || (!isMine.value && !classId.value)) return
  loading.value = true
  try {
    const url = isMine.value ? '/timetables/mine' : `/timetables/classes/${classId.value}`
    timetable.value = (await http.get(url, {
      params: { academicTermId: termId.value },
    })).data
  } catch (error) {
    timetable.value = null
    ElMessage.error(apiErrorMessage(error))
  } finally {
    loading.value = false
  }
}

watch([termId, classId], loadTimetable)

onMounted(async () => {
  try {
    await loadOptions()
    await loadTimetable()
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  }
})
</script>

<template>
  <main :class="['timetable-page', { 'public-timetable': isPublic }]">
    <header v-if="isPublic" class="public-header">
      <router-link class="public-brand" to="/timetable">明序教务 · 课表查询</router-link>
      <router-link class="login-link" to="/login">登录工作台</router-link>
    </header>

    <section class="timetable-heading">
      <div>
        <span class="section-kicker">{{ isMine ? 'MY TIMETABLE' : 'CLASS TIMETABLE' }}</span>
        <h2>{{ isMine ? '我的课表' : '班级课表查询' }}</h2>
        <p v-if="isMine">行政班课程与本人已选课程统一展示，仅采用教务处已发布课表。</p>
        <p v-else>无需登录即可查询各行政班已正式发布的课程安排。</p>
      </div>
      <div class="timetable-filters">
        <el-select v-model="termId" filterable placeholder="选择学期">
          <el-option
            v-for="term in terms"
            :key="term.id"
            :label="`${term.name}${term.hasPublishedTimetable ? '' : '（未发布）'}`"
            :value="term.id"
          />
        </el-select>
        <el-select
          v-if="!isMine"
          v-model="classId"
          filterable
          placeholder="选择行政班"
        >
          <el-option
            v-for="item in classes"
            :key="item.id"
            :label="`${item.collegeName} · ${item.majorName} · ${item.name}`"
            :value="item.id"
          />
        </el-select>
      </div>
    </section>

    <section v-loading="loading" class="timetable-sheet">
      <div v-if="timetable" class="sheet-meta">
        <div>
          <strong>{{ timetable.class.name }}</strong>
          <span>{{ timetable.class.collegeName }} · {{ timetable.class.majorName }}</span>
        </div>
        <div v-if="timetable.student">
          <strong>{{ timetable.student.name }}</strong>
          <span>{{ timetable.student.studentNumber }}</span>
        </div>
        <div>
          <strong>{{ timetable.term.name }}</strong>
          <span v-if="timetable.plan">发布于 {{ new Date(timetable.plan.publishedAt).toLocaleString('zh-CN') }}</span>
          <span v-else>本学期课表尚未发布</span>
        </div>
       </div>

      <section v-if="timetable?.flexibleCourses?.length" class="flexible-courses">
        <div class="flexible-heading">
          <div>
            <span>非排时课程</span>
            <strong>不占正常上课时间与场地</strong>
          </div>
          <small>共 {{ timetable.flexibleCourses.length }} 门</small>
        </div>
        <div class="flexible-course-list">
          <article v-for="course in timetable.flexibleCourses" :key="course.id">
            <span>{{ course.courseCode }} · {{ course.taskNumber }}</span>
            <strong>{{ course.courseName }}</strong>
            <p>{{ course.teacherNames.join('、') || '教师待定' }}</p>
            <small>
              第 {{ course.startWeek }}—{{ course.endWeek }} 周 ·
              每周 {{ course.weeklyHours }} 学时 · 共 {{ course.totalHours }} 学时
            </small>
          </article>
        </div>
      </section>

      <div v-if="timetable?.plan && timetable.entries.length" class="timetable-scroll">
        <div
          class="week-grid"
          :style="{ gridTemplateRows: `48px repeat(${maxPeriods}, 110px)` }"
        >
          <div class="grid-corner">节次</div>
          <div v-for="day in 7" :key="`head-${day}`" class="day-head">{{ weekdays[day] }}</div>
          <template v-for="period in maxPeriods" :key="`period-${period}`">
            <div class="period-head" :style="{ gridRow: String(period + 1) }">
              <strong>第 {{ period }} 节</strong>
              <span v-if="slotMap.get(period)">
                {{ formatTime(slotMap.get(period).startsAt) }}—{{ formatTime(slotMap.get(period).endsAt) }}
              </span>
            </div>
            <div
              v-for="day in 7"
              :key="`cell-${period}-${day}`"
              class="grid-cell"
              :style="{ gridColumn: String(day + 1), gridRow: String(period + 1) }"
            />
          </template>
          <article
            v-for="entry in timetable.entries"
            :key="entry.id"
            class="course-block"
            :style="entryStyle(entry)"
          >
            <strong>{{ entry.courseName }}</strong>
            <span>{{ entry.teacherNames.join('、') || '教师待定' }}</span>
            <span>{{ location(entry) }}</span>
            <small>{{ weeks(entry) }} · 第 {{ entry.startPeriod }}—{{ entry.startPeriod + entry.periodCount - 1 }} 节</small>
          </article>
        </div>
      </div>
      <el-empty
        v-else-if="timetable && !loading && !timetable.flexibleCourses?.length"
        :description="timetable.plan ? '该课表暂时没有课程安排' : '所选学期尚未发布课表'"
      />
    </section>
  </main>
</template>

<style scoped>
.timetable-page { min-width: 0; width: 100%; display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; }
.public-timetable { max-width: 100vw; min-height: 100vh; padding: 0 32px 40px; box-sizing: border-box; background: #f4f7fa; }
.public-header { height: 68px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #dce4eb; }
.public-brand { color: #17324d; font-weight: 750; text-decoration: none; letter-spacing: .02em; }
.login-link { color: #176b87; text-decoration: none; font-weight: 650; }
.timetable-heading { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 24px; padding: 24px 28px; background: #fff; border: 1px solid #dce4eb; }
.timetable-heading h2 { margin: 5px 0 8px; color: #17324d; font-size: 27px; }
.timetable-heading p { margin: 0; color: #647587; }
.timetable-filters { display: flex; flex-wrap: wrap; gap: 12px; }
.timetable-filters .el-select { width: 270px; }
.timetable-sheet { min-width: 0; min-height: 360px; padding: 22px; background: #fff; border: 1px solid #dce4eb; }
.sheet-meta { display: flex; justify-content: space-between; gap: 24px; margin-bottom: 18px; padding-bottom: 16px; border-bottom: 1px solid #e6ebf0; }
.sheet-meta div { display: grid; gap: 3px; }
.sheet-meta strong { color: #17324d; }
.sheet-meta span { color: #718191; font-size: 13px; }
.flexible-courses { margin-bottom: 20px; border: 1px solid #cfe1dc; background: #f5faf8; }
.flexible-heading { padding: 12px 15px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #dce9e5; }
.flexible-heading > div { display: flex; align-items: baseline; gap: 10px; }
.flexible-heading span { color: #176b5d; font-size: 12px; font-weight: 750; }
.flexible-heading strong { color: #506c65; font-size: 12px; }
.flexible-heading small { color: #718b84; }
.flexible-course-list { padding: 12px; display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; }
.flexible-course-list article { padding: 12px 13px; display: grid; gap: 4px; border-left: 3px solid #2d8975; background: #fff; }
.flexible-course-list article > span { color: #277766; font: 700 10px/1.3 Consolas, monospace; }
.flexible-course-list article strong { color: #173f38; font-size: 14px; }
.flexible-course-list article p { margin: 0; color: #5e746f; font-size: 12px; }
.flexible-course-list article small { color: #778b86; font-size: 11px; }
.timetable-scroll { overflow: auto; }
.week-grid { min-width: 1120px; display: grid; grid-template-columns: 92px repeat(7, minmax(140px, 1fr)); position: relative; }
.grid-corner, .day-head, .period-head { z-index: 2; background: #f3f6f8; border: 1px solid #dce4eb; color: #3f5366; }
.grid-corner, .day-head { display: grid; place-items: center; font-weight: 700; }
.grid-corner { grid-column: 1; grid-row: 1; }
.day-head { grid-row: 1; }
.day-head:nth-of-type(2) { grid-column: 2; }
.day-head:nth-of-type(3) { grid-column: 3; }
.day-head:nth-of-type(4) { grid-column: 4; }
.day-head:nth-of-type(5) { grid-column: 5; }
.day-head:nth-of-type(6) { grid-column: 6; }
.day-head:nth-of-type(7) { grid-column: 7; }
.day-head:nth-of-type(8) { grid-column: 8; }
.period-head { grid-column: 1; display: grid; place-content: center; gap: 4px; text-align: center; }
.period-head span { color: #7c8b98; font-size: 11px; }
.grid-cell { border: 1px solid #e4e9ee; background: #fff; }
.course-block { z-index: 3; margin: 4px; padding: 9px 10px; overflow: hidden; display: flex; flex-direction: column; gap: 4px; border-left: 4px solid #176b87; background: #e9f3f5; color: #24475a; box-shadow: 0 2px 5px rgba(23, 50, 77, .08); }
.course-block strong { color: #123a4b; font-size: 14px; }
.course-block span { font-size: 12px; }
.course-block small { margin-top: auto; color: #5f7885; font-size: 11px; }
@media (max-width: 760px) {
  .public-timetable { padding: 0 14px 24px; }
  .timetable-heading, .sheet-meta { align-items: stretch; flex-direction: column; }
  .timetable-filters { flex-direction: column; }
  .timetable-filters .el-select { width: 100%; }
  .timetable-sheet { padding: 12px; }
}
</style>
