<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { Location, Refresh, Search } from '@element-plus/icons-vue'
import http, { apiErrorMessage } from '../api/http'
import { academicTermLabel, academicTermOptionClass } from '../utils/academicTerms'

interface TermOption {
  id: string
  name: string
  startDate: string
  endDate: string
  isCurrent: boolean
  isArchived: boolean
  hasPublishedTimetable: boolean
}

interface PlaceOption {
  id: string
  code: string
  name: string
  campusId?: string
}

interface TimeSlotOption {
  periodNumber: number
  name: string
  startTime: string
  endTime: string
}

interface FreeClassroom {
  id: string
  code: string
  name: string
  capacity: number
  buildingId: string
  buildingName: string
  campusId: string
  campusName: string
}

const weekdayOptions = [
  { value: 1, label: '周一' },
  { value: 2, label: '周二' },
  { value: 3, label: '周三' },
  { value: 4, label: '周四' },
  { value: 5, label: '周五' },
  { value: 6, label: '周六' },
  { value: 7, label: '周日' },
]
const terms = ref<TermOption[]>([])
const campuses = ref<PlaceOption[]>([])
const buildings = ref<PlaceOption[]>([])
const timeSlots = ref<TimeSlotOption[]>([])
const classrooms = ref<FreeClassroom[]>([])
const loading = ref(false)
const searched = ref(false)
const resultPage = ref(1)
const pageSize = 48
const form = reactive({
  academicTermId: '',
  week: 1,
  dayOfWeek: new Date().getDay() || 7,
  startPeriod: 1,
  periodCount: 1,
  campusId: '',
  buildingId: '',
  minimumCapacity: undefined as number | undefined,
})

const selectedTerm = computed(() =>
  terms.value.find((item) => item.id === form.academicTermId),
)
const filteredBuildings = computed(() =>
  buildings.value.filter((item) => !form.campusId || item.campusId === form.campusId),
)
const availableStartPeriods = computed(() =>
  timeSlots.value.filter((slot) =>
    timeSlots.value.some((candidate) =>
      candidate.periodNumber === slot.periodNumber + form.periodCount - 1,
    ),
  ),
)
const pagedClassrooms = computed(() =>
  classrooms.value.slice((resultPage.value - 1) * pageSize, resultPage.value * pageSize),
)
const groupedRooms = computed(() => {
  const groups = new Map<string, { campusName: string; buildingName: string; rooms: FreeClassroom[] }>()
  for (const room of pagedClassrooms.value) {
    const key = `${room.campusId}:${room.buildingId}`
    const group = groups.get(key) ?? {
      campusName: room.campusName,
      buildingName: room.buildingName,
      rooms: [],
    }
    group.rooms.push(room)
    groups.set(key, group)
  }
  return [...groups.values()]
})
const querySummary = computed(() => {
  const day = weekdayOptions.find((item) => item.value === form.dayOfWeek)?.label ?? ''
  const end = form.startPeriod + form.periodCount - 1
  const periods = end === form.startPeriod
    ? `第 ${form.startPeriod} 节`
    : `第 ${form.startPeriod}—${end} 节`
  return `第 ${form.week} 周 · ${day} · ${periods}`
})

function calculateCurrentWeek(term?: TermOption) {
  if (!term) return 1
  const start = new Date(`${term.startDate}T00:00:00`)
  const today = new Date()
  const week = Math.floor((today.getTime() - start.getTime()) / 604800000) + 1
  return Math.min(30, Math.max(1, week))
}

function onCampusChanged() {
  if (!filteredBuildings.value.some((item) => item.id === form.buildingId)) {
    form.buildingId = ''
  }
}

async function loadOptions(academicTermId?: string) {
  try {
    const { data } = await http.get('/timetables/free-classrooms/options', {
      params: academicTermId ? { academicTermId } : undefined,
    })
    terms.value = data.terms
    campuses.value = data.campuses
    buildings.value = data.buildings
    timeSlots.value = data.timeSlots
    if (!form.academicTermId) {
      form.academicTermId = data.selectedTermId ?? ''
      form.week = calculateCurrentWeek(
        terms.value.find((item) => item.id === form.academicTermId),
      )
    }
    if (!availableStartPeriods.value.some(
      (item) => item.periodNumber === form.startPeriod,
    )) {
      form.startPeriod = availableStartPeriods.value[0]?.periodNumber ?? 1
    }
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  }
}

async function onTermChanged() {
  form.week = calculateCurrentWeek(selectedTerm.value)
  classrooms.value = []
  searched.value = false
  await loadOptions(form.academicTermId)
}

async function searchRooms() {
  if (!form.academicTermId) {
    ElMessage.warning('请先选择学期。')
    return
  }
  loading.value = true
  try {
    const { data } = await http.get('/timetables/free-classrooms', {
      params: {
        academicTermId: form.academicTermId,
        week: form.week,
        dayOfWeek: form.dayOfWeek,
        startPeriod: form.startPeriod,
        periodCount: form.periodCount,
        campusId: form.campusId || undefined,
        buildingId: form.buildingId || undefined,
        minimumCapacity: form.minimumCapacity,
      },
    })
    classrooms.value = data.items
    resultPage.value = 1
    searched.value = true
  } catch (error) {
    classrooms.value = []
    searched.value = false
    ElMessage.error(apiErrorMessage(error))
  } finally {
    loading.value = false
  }
}

onMounted(async () => {
  await loadOptions()
})
</script>

<template>
  <section class="free-room-page">
    <header class="page-heading">
      <div>
        <span class="eyebrow">STUDENT SERVICE · 空间查询</span>
        <h2>空闲教室查询</h2>
        <p>依据已发布课表，查询指定周次和连续节次内没有排课的教学场所。</p>
      </div>
      <el-tag type="success" effect="plain">仅使用正式课表</el-tag>
    </header>

    <el-card shadow="never" class="query-card">
      <el-form label-position="top" class="query-form">
        <el-form-item label="学期">
          <el-select v-model="form.academicTermId" @change="onTermChanged">
            <el-option
              v-for="term in terms"
              :key="term.id"
              :label="academicTermLabel(term)"
              :value="term.id"
              :class="academicTermOptionClass(term)"
              :disabled="!term.hasPublishedTimetable"
            >
              <span>{{ term.name }}</span>
              <small v-if="!term.hasPublishedTimetable">尚未发布课表</small>
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="周次">
          <el-input-number v-model="form.week" :min="1" :max="30" />
        </el-form-item>
        <el-form-item label="星期">
          <el-select v-model="form.dayOfWeek">
            <el-option
              v-for="item in weekdayOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="开始节次">
          <el-select v-model="form.startPeriod">
            <el-option
              v-for="slot in availableStartPeriods"
              :key="slot.periodNumber"
              :label="slot.startTime
                ? `${slot.name}（${slot.startTime.slice(0, 5)}—${slot.endTime.slice(0, 5)}）`
                : slot.name"
              :value="slot.periodNumber"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="连续节数">
          <el-input-number v-model="form.periodCount" :min="1" :max="6" />
        </el-form-item>
        <el-form-item label="校区">
          <el-select v-model="form.campusId" clearable placeholder="全部校区" @change="onCampusChanged">
            <el-option
              v-for="campus in campuses"
              :key="campus.id"
              :label="campus.name"
              :value="campus.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="教学楼">
          <el-select v-model="form.buildingId" clearable placeholder="全部教学楼">
            <el-option
              v-for="building in filteredBuildings"
              :key="building.id"
              :label="building.name"
              :value="building.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="至少容纳人数">
          <el-input-number
            v-model="form.minimumCapacity"
            :min="0"
            :max="10000"
            placeholder="不限"
          />
        </el-form-item>
        <div class="query-action">
          <el-button type="primary" :icon="Search" :loading="loading" @click="searchRooms">
            查询空闲教室
          </el-button>
        </div>
      </el-form>
    </el-card>

    <section v-loading="loading" class="result-panel">
      <div class="result-heading">
        <div>
          <span>查询条件</span>
          <h3>{{ querySummary }}</h3>
        </div>
        <div v-if="searched" class="result-count">
          <strong>{{ classrooms.length }}</strong>
          <span>间空闲教室</span>
        </div>
        <el-button v-if="searched" text :icon="Refresh" @click="searchRooms">刷新</el-button>
      </div>

      <template v-if="searched && groupedRooms.length">
        <div class="building-groups">
          <article v-for="group in groupedRooms" :key="`${group.campusName}-${group.buildingName}`">
            <header>
              <el-icon><Location /></el-icon>
              <div>
                <small>{{ group.campusName }}</small>
                <h4>{{ group.buildingName }}</h4>
              </div>
              <span>{{ group.rooms.length }} 间</span>
            </header>
            <div class="room-grid">
              <div v-for="room in group.rooms" :key="room.id" class="room-item">
                <b>{{ room.name }}</b>
                <span>{{ room.code }}</span>
                <em>容纳 {{ room.capacity }} 人</em>
              </div>
            </div>
          </article>
        </div>
        <el-pagination
          v-if="classrooms.length > pageSize"
          v-model:current-page="resultPage"
          class="result-pagination"
          background
          layout="prev, pager, next, jumper"
          :page-size="pageSize"
          :total="classrooms.length"
        />
      </template>
      <el-empty
        v-else-if="searched"
        description="当前条件下没有空闲教室，可尝试缩短连续节数或调整场地范围。"
      />
      <el-empty v-else description="设置条件后查询空闲教室" />
    </section>
  </section>
</template>

<style scoped>
.free-room-page {
  display: grid;
  gap: 20px;
}

.page-heading,
.result-heading,
.result-count,
.building-groups article > header,
.room-item {
  display: flex;
  align-items: center;
}

.page-heading {
  justify-content: space-between;
  gap: 24px;
}

.eyebrow {
  color: #17867c;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
}

h2,
h3,
h4,
p {
  margin: 0;
}

h2 {
  margin-top: 5px;
  color: #183b56;
  font-size: 25px;
}

.page-heading p {
  margin-top: 8px;
  color: #718096;
}

.query-card {
  border-color: #dce6eb;
}

.query-form {
  display: grid;
  grid-template-columns: repeat(4, minmax(150px, 1fr));
  gap: 2px 16px;
  align-items: end;
}

.query-form :deep(.el-form-item) {
  margin-bottom: 12px;
}

.query-form :deep(.el-select),
.query-form :deep(.el-input-number) {
  width: 100%;
}

.query-form small {
  float: right;
  margin-left: 12px;
  color: #a0aec0;
}

.query-action {
  padding-bottom: 12px;
}

.query-action .el-button {
  width: 100%;
}

.result-panel {
  min-height: 260px;
  padding: 22px;
  border: 1px solid #dce6eb;
  background: #fff;
}

.result-heading {
  gap: 18px;
  padding-bottom: 18px;
  border-bottom: 1px solid #edf2f5;
}

.result-heading > div:first-child {
  flex: 1;
}

.result-heading span,
.building-groups small,
.room-item span {
  color: #718096;
  font-size: 13px;
}

.result-heading h3 {
  margin-top: 3px;
  color: #24445d;
  font-size: 17px;
}

.result-count {
  gap: 7px;
}

.result-count strong {
  color: #16867c;
  font-size: 24px;
}

.building-groups {
  display: grid;
  gap: 18px;
  margin-top: 20px;
}

.result-pagination {
  justify-content: flex-end;
  margin-top: 20px;
}

.building-groups article {
  border: 1px solid #dfe8ec;
}

.building-groups article > header {
  gap: 10px;
  padding: 13px 16px;
  border-bottom: 1px solid #e7eef1;
  background: #f5faf9;
  color: #17867c;
}

.building-groups article > header div {
  flex: 1;
}

.building-groups h4 {
  margin-top: 2px;
  color: #24445d;
}

.building-groups article > header > span {
  color: #17867c;
  font-size: 13px;
  font-weight: 700;
}

.room-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 1px;
  background: #e7eef1;
}

.room-item {
  min-height: 92px;
  align-items: flex-start;
  flex-direction: column;
  padding: 14px;
  background: #fff;
}

.room-item b {
  color: #24445d;
}

.room-item em {
  margin-top: auto;
  color: #17867c;
  font-size: 13px;
  font-style: normal;
}

@media (max-width: 1000px) {
  .query-form {
    grid-template-columns: repeat(2, minmax(150px, 1fr));
  }
}

@media (max-width: 600px) {
  .page-heading,
  .result-heading {
    align-items: flex-start;
    flex-direction: column;
  }

  .query-form {
    grid-template-columns: 1fr;
  }

  .result-panel {
    padding: 16px;
  }
}
</style>
