<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  getAllGroupCourses,
  createGroupCourse,
  updateGroupCourse,
  deleteGroupCourse,
  restoreGroupCourse,
  uploadImage,
  getPresignedUrl,
} from '@/api/modules/groupCourse'
import { getAllGroupCourseTypes } from '@/api/modules/groupCourseType'
import { formatDate } from '@/utils/format'

interface CourseItem {
  id: number
  courseName: string
  coachId: number
  courseType: number
  startTime: string | null
  endTime: string | null
  maxMembers: number
  currentMembers: number
  status: number
  location: string
  coverImage: string | null
  description: string
  storedValueAmount: number
  createdAt: string | null
  updatedAt: string | null
  deletedAt: string | null
}

// ---- State ----
const loading = ref(false)
const list = ref<CourseItem[]>([])
const total = ref(0)
const typeMap = ref<Record<number, string>>({})

// stats (from full dataset)
const allCourses = ref<CourseItem[]>([])
const statsNonDeleted = ref({ total: 0, normal: 0, cancelled: 0, ended: 0, deleted: 0 })
const stats = computed(() => statsNonDeleted.value)

// filters
const keyword = ref('')
const typeFilter = ref<number | null>(null)
const statusFilter = ref<number | null>(null)
const dateRange = ref<[string, string] | null>(null)
const timePeriod = ref<string | null>(null)

// sorting
type SortMode = 'default' | 'priceAsc' | 'priceDesc' | 'remainingMost'
const sortMode = ref<SortMode>('default')

const currentPage = ref(0)
const pageSize = ref(10)

const displayPage = computed({
  get: () => currentPage.value + 1,
  set: (val: number) => {
    currentPage.value = val - 1
    applyPage()
  },
})

// dialogs
const dialogVisible = ref(false)
const isEdit = ref(false)
const saving = ref(false)
const adminPassword = ref('')
const pendingCoverFile = ref<File | null>(null)
const coverPreviewUrl = ref('')

const form = reactive({
  id: 0,
  courseName: '',
  coachId: null as number | null,
  courseType: null as number | null,
  startTime: '',
  endTime: '',
  maxMembers: 20,
  currentMembers: 0,
  status: 0,
  location: '',
  coverImage: '',
  description: '',
  storedValueAmount: 0,
})

const coverUrlMap = ref<Record<number, string>>({})

// ---- Helpers ----
const toNum = (v: any): number => Number(v)
const statusLabel = (s: any) => {
  const map: Record<number, string> = { 0: '正常', 1: '已取消', 2: '已结束' }
  return map[toNum(s)] ?? '未知'
}
const statusTagType = (s: any) => {
  const map: Record<number, string> = { 0: 'success', 1: 'danger', 2: 'info' }
  return map[toNum(s)] ?? 'info'
}
const isDeleted = (row: CourseItem) => row.deletedAt != null

// ---- Methods ----
async function fetchTypes() {
  try {
    const res: any = await getAllGroupCourseTypes()
    const map: Record<number, string> = {}
    if (Array.isArray(res)) {
      res.forEach((t: any) => {
        if (t.id != null && t.typeName) map[t.id] = t.typeName
      })
    }
    typeMap.value = map
  } catch {
    /* ignore */
  }
}

async function fetchStats() {
  try {
    // 未删除的课程（用于统计）
    const res: any = await getAllGroupCourses(false)
    const courses: CourseItem[] = Array.isArray(res) ? res : []
    statsNonDeleted.value = {
      total: courses.length,
      normal: courses.filter((m) => toNum(m.status) === 0).length,
      cancelled: courses.filter((m) => toNum(m.status) === 1).length,
      ended: courses.filter((m) => toNum(m.status) === 2).length,
      deleted: 0,
    }
    // 同时获取已删除课程数
    const allRes: any = await getAllGroupCourses(true)
    const allCoursesData: CourseItem[] = Array.isArray(allRes) ? allRes : []
    statsNonDeleted.value.deleted = allCoursesData.filter((m) => m.deletedAt != null).length
  } catch {
    statsNonDeleted.value = { total: 0, normal: 0, cancelled: 0, ended: 0, deleted: 0 }
  }
}

async function fetchCoverUrls() {
  const newMap: Record<number, string> = {}
  for (const course of allCourses.value) {
    if (course.coverImage) {
      try {
        const res = await getPresignedUrl(course.coverImage)
        if (res.code === 200 && res.data?.presignedUrl) {
          newMap[course.id] = res.data.presignedUrl
        }
      } catch {
        // ignore individual failures
      }
    }
  }
  coverUrlMap.value = newMap
}

async function loadData() {
  loading.value = true
  await fetchStats()
  // 根据筛选状态加载数据
  if (statusFilter.value === 3) {
    try {
      const res: any = await getAllGroupCourses(true)
      allCourses.value = (Array.isArray(res) ? res : []).filter((m: CourseItem) => m.deletedAt != null)
    } catch {
      allCourses.value = []
    }
  } else {
    try {
      const res: any = await getAllGroupCourses(false)
      allCourses.value = Array.isArray(res) ? res : []
    } catch {
      allCourses.value = []
    }
  }
  await fetchCoverUrls()
  loading.value = false
  applyPage()
}

function applyFilters(): CourseItem[] {
  let data = [...allCourses.value]

  // keyword filter (course name fuzzy)
  if (keyword.value) {
    const kw = keyword.value.toLowerCase()
    data = data.filter((item) =>
      (item.courseName || '').toLowerCase().includes(kw)
    )
  }

  // type filter
  if (typeFilter.value != null) {
    data = data.filter((item) => item.courseType === typeFilter.value)
  }

  // status filter（值 3 为"已删除"，已在 loadData 数据源层处理，此处跳过）
  if (statusFilter.value != null && statusFilter.value !== 3) {
    data = data.filter((item) => toNum(item.status) === statusFilter.value)
  }

  // date range filter
  if (dateRange.value) {
    const [start, end] = dateRange.value
    if (start) {
      data = data.filter((item) => item.startTime && item.startTime >= `${start}T00:00:00`)
    }
    if (end) {
      data = data.filter((item) => item.startTime && item.startTime <= `${end}T23:59:59`)
    }
  }

  // time period filter
  if (timePeriod.value) {
    data = data.filter((item) => {
      if (!item.startTime) return false
      const hour = new Date(item.startTime).getHours()
      switch (timePeriod.value) {
        case 'morning':
          return hour >= 6 && hour < 12
        case 'afternoon':
          return hour >= 12 && hour < 18
        case 'evening':
          return hour >= 18
        default:
          return true
      }
    })
  }

  // sorting
  if (sortMode.value === 'priceAsc') {
    data.sort((a, b) => (a.storedValueAmount ?? 0) - (b.storedValueAmount ?? 0))
  } else if (sortMode.value === 'priceDesc') {
    data.sort((a, b) => (b.storedValueAmount ?? 0) - (a.storedValueAmount ?? 0))
  } else if (sortMode.value === 'remainingMost') {
    data.sort((a, b) => {
      const remainA = (a.maxMembers ?? 0) - (a.currentMembers ?? 0)
      const remainB = (b.maxMembers ?? 0) - (b.currentMembers ?? 0)
      return remainB - remainA
    })
  } else {
    // default: id descending
    data.sort((a, b) => (b.id ?? 0) - (a.id ?? 0))
  }

  return data
}

function applyPage() {
  const filtered = applyFilters()
  total.value = filtered.length
  const start = currentPage.value * pageSize.value
  list.value = filtered.slice(start, start + pageSize.value)
}

function handleSearch() {
  currentPage.value = 0
  loadData()
}

function resetFilters() {
  const wasDeleted = statusFilter.value === 3
  keyword.value = ''
  typeFilter.value = null
  statusFilter.value = null
  dateRange.value = null
  timePeriod.value = null
  sortMode.value = 'default'
  currentPage.value = 0
  if (wasDeleted) {
    loadData()
  } else {
    applyPage()
  }
}

// watch sortMode to re-paginate
watch(sortMode, () => {
  currentPage.value = 0
  applyPage()
})

// 切换“已删除”筛选时重新加载数据
watch(statusFilter, (newVal, oldVal) => {
  if (newVal === 3 || oldVal === 3) {
    currentPage.value = 0
    loadData()
  } else {
    currentPage.value = 0
    applyPage()
  }
})

// ---- Create / Edit ----
function openCreate() {
  isEdit.value = false
  adminPassword.value = ''
  pendingCoverFile.value = null
  coverPreviewUrl.value = ''
  Object.assign(form, {
    id: 0,
    courseName: '',
    coachId: null,
    courseType: null,
    startTime: '',
    endTime: '',
    maxMembers: 20,
    currentMembers: 0,
    status: 0,
    location: '',
    coverImage: '',
    description: '',
    storedValueAmount: 0,
  })
  dialogVisible.value = true
}

function openEdit(row: CourseItem) {
  isEdit.value = true
  adminPassword.value = ''
  pendingCoverFile.value = null
  coverPreviewUrl.value = ''
  form.id = row.id
  form.courseName = row.courseName || ''
  form.coachId = row.coachId ?? null
  form.courseType = toNum(row.courseType)
  form.maxMembers = row.maxMembers ?? 20
  form.currentMembers = row.currentMembers ?? 0
  form.status = toNum(row.status)
  form.location = row.location || ''
  form.coverImage = row.coverImage || ''
  form.description = row.description || ''
  form.storedValueAmount = row.storedValueAmount ?? 0
  form.startTime = row.startTime ? formatDate(row.startTime, 'YYYY-MM-DD HH:mm:ss') : ''
  form.endTime = row.endTime ? formatDate(row.endTime, 'YYYY-MM-DD HH:mm:ss') : ''
  dialogVisible.value = true
  // 如果有已有封面，获取预签名URL用于预览
  if (form.coverImage) {
    getPresignedUrl(form.coverImage).then((res) => {
      if (res.code === 200 && res.data?.presignedUrl) {
        coverPreviewUrl.value = res.data.presignedUrl
      }
    }).catch(() => {})
  }
}

function onUploadChange(uploadFile: any) {
  const rawFile = uploadFile?.raw || uploadFile
  if (rawFile) {
    pendingCoverFile.value = rawFile
    if (coverPreviewUrl.value) URL.revokeObjectURL(coverPreviewUrl.value)
    coverPreviewUrl.value = URL.createObjectURL(rawFile)
  }
}

function handleImgError(e: Event) {
  const img = e.target as HTMLImageElement
  img.style.display = 'none'
  const fallback = img.nextElementSibling as HTMLElement | null
  if (fallback) fallback.style.display = ''
}

function handleDialogClosed() {
  Object.assign(form, { startTime: '', endTime: '' })
  adminPassword.value = ''
  if (coverPreviewUrl.value) {
    URL.revokeObjectURL(coverPreviewUrl.value)
    coverPreviewUrl.value = ''
  }
  pendingCoverFile.value = null
}

async function handleSave() {
  saving.value = true
  try {
    const body: any = { ...form }
    delete body.id
    if (body.startTime) body.startTime = new Date(body.startTime).toISOString()
    if (body.endTime) body.endTime = new Date(body.endTime).toISOString()

    if (isEdit.value) {
      if (!adminPassword.value) {
        ElMessage.warning('请输入管理员密码')
        saving.value = false
        return
      }
      // upload cover if user selected a new one
      if (pendingCoverFile.value) {
        const res: any = await uploadImage(pendingCoverFile.value)
        if (res.code === 200) {
          body.coverImage = res.data.ossKey
        } else {
          ElMessage.error(res.message || '封面上传失败')
          saving.value = false
          return
        }
      }
      await updateGroupCourse(form.id, body, { params: { adminPassword: adminPassword.value } })
    } else {
      if (pendingCoverFile.value) {
        const res: any = await uploadImage(pendingCoverFile.value)
        if (res.code === 200) {
          body.coverImage = res.data.ossKey
        } else {
          ElMessage.error(res.message || '封面上传失败')
          saving.value = false
          return
        }
      }
      await createGroupCourse(body)
    }
    ElMessage.success(isEdit.value ? '更新成功' : '创建成功')
    dialogVisible.value = false
    loadData()
  } catch {
    ElMessage.error('操作失败')
  } finally {
    saving.value = false
  }
}

async function handleDelete(row: CourseItem) {
  try {
    await ElMessageBox.confirm(`确定要删除团课"${row.courseName}"吗？`, '确认删除', { type: 'warning' })
    const { value: pwd } = await ElMessageBox.prompt('请输入管理员密码以确认删除', '管理员验证', {
      inputType: 'password',
      confirmButtonText: '确认删除',
      cancelButtonText: '取消',
    })
    if (!pwd) return
    await deleteGroupCourse(row.id, { params: { adminPassword: pwd } })
    ElMessage.success('已删除')
    loadData()
  } catch (e: any) {
    if (e !== 'cancel' && e?.message !== 'cancel') {
      // error already shown by axios interceptor
    }
  }
}

async function handleRestore(row: CourseItem) {
  try {
    await ElMessageBox.confirm(`确定要恢复团课"${row.courseName}"为已取消状态吗？`, '确认恢复', { type: 'info' })
    const { value: pwd } = await ElMessageBox.prompt('请输入管理员密码以确认恢复', '管理员验证', {
      inputType: 'password',
      confirmButtonText: '确认恢复',
      cancelButtonText: '取消',
    })
    if (!pwd) return
    await restoreGroupCourse(row.id, { params: { adminPassword: pwd } })
    ElMessage.success('已恢复')
    loadData()
  } catch (e: any) {
    if (e !== 'cancel' && e?.message !== 'cancel') {
      // error already shown by axios interceptor
    }
  }
}

onMounted(() => {
  fetchTypes()
  loadData()
})
</script>

<template>
  <div>
    <h2 style="margin-bottom: 16px">团课列表</h2>

    <!-- Stats -->
    <el-row :gutter="16" style="margin-bottom: 16px">
      <el-col :span="4" v-for="s in [
        { label: '团课总数', value: stats.total, color: '#1890ff' },
        { label: '正常进行', value: stats.normal, color: '#52c41a' },
        { label: '已取消', value: stats.cancelled, color: '#ff4d4f' },
        { label: '已结束', value: stats.ended, color: '#909399' },
        { label: '已删除', value: stats.deleted, color: '#fa8c16' },
      ]" :key="s.label">
        <el-card shadow="hover">
          <div style="text-align: center">
            <div style="font-size: 26px; font-weight: bold" :style="{ color: s.color }">
              {{ s.value }}
            </div>
            <div style="color: var(--text-secondary); margin-top: 4px; font-size: 13px">{{ s.label }}</div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- Search -->
    <el-card class="search-card">
      <el-form inline>
        <el-form-item label="课程名称">
          <el-input
            v-model="keyword"
            placeholder="请输入课程名称"
            clearable
            style="width: 180px"
            @keyup.enter="handleSearch"
          />
        </el-form-item>
        <el-form-item label="课程类型">
          <el-select v-model="typeFilter" placeholder="全部" clearable style="width: 130px">
            <el-option
              v-for="(name, id) in typeMap"
              :key="id"
              :label="name"
              :value="Number(id)"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="statusFilter" placeholder="全部" clearable style="width: 100px">
            <el-option label="正常" :value="0" />
            <el-option label="已取消" :value="1" />
            <el-option label="已结束" :value="2" />
            <el-option label="已删除" :value="3" />
          </el-select>
        </el-form-item>
        <el-form-item label="日期范围">
          <el-date-picker
            v-model="dateRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            value-format="YYYY-MM-DD"
            style="width: 230px"
          />
        </el-form-item>
        <el-form-item label="时间段">
          <el-select v-model="timePeriod" placeholder="全部" clearable style="width: 100px">
            <el-option label="早晨" value="morning" />
            <el-option label="下午" value="afternoon" />
            <el-option label="夜晚" value="evening" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">搜索</el-button>
          <el-button @click="resetFilters">重置</el-button>
        </el-form-item>
      </el-form>

      <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 8px">
        <el-button type="primary" @click="openCreate" v-permission="'business:groupCourse:create'">+ 新增团课</el-button>

        <div style="display: flex; align-items: center; gap: 10px">
          <span style="color: var(--text-secondary); font-size: 13px">排序:</span>
          <el-select v-model="sortMode" style="width: 180px" size="default">
            <el-option label="默认排序(ID倒序)" value="default" />
            <el-option label="价格从低到高" value="priceAsc" />
            <el-option label="价格从高到低" value="priceDesc" />
            <el-option label="剩余名额最多" value="remainingMost" />
          </el-select>
        </div>
      </div>
    </el-card>

    <!-- Table -->
    <el-card>
      <el-table :data="list" v-loading="loading" stripe highlight-current-row>
        <el-table-column prop="id" label="团课ID" width="110" align="center" />

        <el-table-column prop="courseName" label="课程名称" min-width="150" show-overflow-tooltip />

        <el-table-column label="课程类型" width="110">
          <template #default="{ row }">
            {{ typeMap[row.courseType] || row.courseType || '-' }}
          </template>
        </el-table-column>

        <el-table-column label="封面" width="72" align="center">
          <template #default="{ row }">
            <template v-if="row.coverImage && coverUrlMap[row.id]">
              <img
                :src="coverUrlMap[row.id]"
                style="width: 56px; height: 40px; object-fit: cover; border-radius: 4px; border: 1px solid #dcdfe6"
                @error="handleImgError"
              />
              <span style="display: none; color: #c0c4cc; font-size: 18px">✕</span>
            </template>
            <span v-else style="color: #c0c4cc; font-size: 18px">✕</span>
          </template>
        </el-table-column>

        <el-table-column label="上课时间" width="170">
          <template #default="{ row }">
            {{ row.startTime ? formatDate(row.startTime, 'MM-DD HH:mm') : '-' }}
          </template>
        </el-table-column>

        <el-table-column label="下课时间" width="170">
          <template #default="{ row }">
            {{ row.endTime ? formatDate(row.endTime, 'MM-DD HH:mm') : '-' }}
          </template>
        </el-table-column>

        <el-table-column prop="location" label="上课地点" min-width="120" show-overflow-tooltip />

        <el-table-column label="报名/上限" width="100" align="center">
          <template #default="{ row }">
            <span :style="{ color: row.currentMembers >= row.maxMembers ? '#ff4d4f' : '' }">
              {{ row.currentMembers ?? 0 }}/{{ row.maxMembers ?? 0 }}
            </span>
          </template>
        </el-table-column>

        <el-table-column label="储值消耗" width="100" align="right">
          <template #default="{ row }">
            {{ row.storedValueAmount != null ? '¥' + Number(row.storedValueAmount).toFixed(2) : '-' }}
          </template>
        </el-table-column>

        <el-table-column label="状态" width="80" align="center">
          <template #default="{ row }">
            <el-tag v-if="isDeleted(row)" type="warning" size="small">已删除</el-tag>
            <el-tag v-else :type="statusTagType(row.status)" size="small">
              {{ statusLabel(row.status) }}
            </el-tag>
          </template>
        </el-table-column>

        <el-table-column label="创建时间" width="170">
          <template #default="{ row }">
            {{ row.createdAt ? formatDate(row.createdAt, 'YYYY-MM-DD HH:mm') : '-' }}
          </template>
        </el-table-column>

        <el-table-column label="操作" width="140" fixed="right">
          <template #default="{ row }">
            <el-button type="primary" link @click="openEdit(row)" v-permission="'business:groupCourse:edit'">编辑</el-button>
            <el-button
              v-if="isDeleted(row)"
              type="success"
              link
              @click="handleRestore(row)"
              v-permission="'business:groupCourse:edit'"
            >恢复</el-button>
            <el-button v-else type="danger" link @click="handleDelete(row)" v-permission="'business:groupCourse:delete'">删除</el-button>
          </template>
        </el-table-column>
      </el-table>

      <div style="margin-top: 16px; display: flex; justify-content: space-between; align-items: center">
        <span style="color: var(--text-secondary); font-size: 13px">
          共 {{ total }} 条记录
        </span>
        <el-pagination
          v-model:current-page="displayPage"
          :page-size="pageSize"
          :total="total"
          layout="prev, pager, next, sizes"
          :page-sizes="[10, 20, 50, 100]"
          @size-change="(s: number) => { pageSize = s; currentPage = 0; applyPage() }"
        />
      </div>
    </el-card>

    <!-- Create / Edit Dialog -->
    <el-dialog
      v-model="dialogVisible"
      :title="isEdit ? '编辑团课' : '新增团课'"
      width="580px"
      :close-on-click-modal="false"
      @closed="handleDialogClosed"
    >
      <el-form :model="form" label-width="100px">
        <el-form-item label="课程名称" required>
          <el-input v-model="form.courseName" placeholder="请输入课程名称" maxlength="50" />
        </el-form-item>
        <el-form-item label="课程类型" required>
          <el-select v-model="form.courseType" placeholder="请选择课程类型" style="width: 100%">
            <el-option
              v-for="(name, id) in typeMap"
              :key="id"
              :label="name"
              :value="Number(id)"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="上课时间">
          <el-date-picker
            v-model="form.startTime"
            type="datetime"
            placeholder="选择上课时间"
            value-format="YYYY-MM-DD HH:mm:ss"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item label="下课时间">
          <el-date-picker
            v-model="form.endTime"
            type="datetime"
            placeholder="选择下课时间"
            value-format="YYYY-MM-DD HH:mm:ss"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item label="上课地点">
          <el-input v-model="form.location" placeholder="请输入上课地点" maxlength="100" />
        </el-form-item>
        <el-row :gutter="16">
          <el-col :span="12">
            <el-form-item label="最大人数">
              <el-input-number v-model="form.maxMembers" :min="1" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="已报名人数">
              <el-input-number v-model="form.currentMembers" :min="0" :max="form.maxMembers" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="状态">
          <el-select v-model="form.status" style="width: 100%">
            <el-option label="正常" :value="0" />
            <el-option label="已取消" :value="1" />
          </el-select>
        </el-form-item>
        <el-form-item label="课程描述">
          <el-input
            v-model="form.description"
            type="textarea"
            :rows="3"
            placeholder="请输入课程描述"
            maxlength="500"
            show-word-limit
          />
        </el-form-item>
        <el-form-item label="封面图片">
          <el-upload
            :auto-upload="false"
            :show-file-list="false"
            accept="image/*"
            :on-change="onUploadChange"
          >
            <template #trigger>
              <el-button type="primary">选择封面图片</el-button>
            </template>
          </el-upload>
          <div v-if="coverPreviewUrl" style="margin-top: 8px">
            <a :href="coverPreviewUrl" target="_blank" :title="coverPreviewUrl">
              <img
                :src="coverPreviewUrl"
                style="width: 180px; height: 100px; object-fit: cover; border-radius: 6px; border: 1px solid #dcdfe6"
                @error="handleImgError"
              />
            </a>
          </div>
        </el-form-item>
        <el-form-item label="储值卡额度">
          <el-input-number v-model="form.storedValueAmount" :min="0" :precision="2" style="width: 200px" />
        </el-form-item>
        <el-form-item v-if="isEdit" label="管理员密码" required>
          <el-input
            v-model="adminPassword"
            type="password"
            placeholder="修改团课信息需要验证管理员密码"
            show-password
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="handleSave">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>
