<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { getTasks, updateTask } from '@/api/taskService.js'
import { getStudents } from '@/api/studentService.js'
import { getSubjects } from '@/api/subjectService.js'
import { getTerms } from '@/api/termService.js'
import { getStories } from '@/api/storyService.js'
import { useTaskImages } from '@/composables/useTaskImages.js'
import { useTaskFilters } from '@/composables/useTaskFilters.js'
import TaskFilters from '@/components/task/TaskFilters.vue'
import TaskCalendar from '@/components/task/TaskCalendar.vue'
import TaskEditDialog from '@/components/task/TaskEditDialog.vue'
import TaskImageCarousel from '@/components/task/TaskImageCarousel.vue'

const { t } = useI18n()

// Shared instances (single useTaskImages + useTaskFilters across the
// page lifetime; both depend on ref data, owned here).
const img = useTaskImages()

// Reference data (loaded once in onMounted)
const students = ref([])
const subjects = ref([])
const terms = ref([])
const stories = ref([])
const tasks = ref([])

// Filter state (parent owns it; TaskFilters is a dumb renderer).
const filterPanel = useTaskFilters({ students, subjects, terms, stories })

// Dialog state
const editDialog = ref(false)
const editingTask = ref(null) // task object for edit, null for create
const creatingDate = ref(null) // initial date when opening create

const imageDialog = ref(false) // carousel
const initialImageId = ref(null)

// Loading / error
const isLoading = ref(false)
const isError = ref(false)
const errorMessage = ref('')

function setError(msg) {
  isError.value = true
  errorMessage.value = msg
}

function clearError() {
  isError.value = false
  errorMessage.value = ''
}

// ─── Reference data fetchers ────────────────────────────────────────
async function fetchStudents() {
  try {
    const data = await getStudents()
    students.value = Array.isArray(data) ? data : []
  } catch (error) {
    console.error('Failed to fetch students:', error)
  }
}
async function fetchSubjects() {
  try {
    const data = await getSubjects()
    subjects.value = Array.isArray(data) ? data : []
  } catch (error) {
    console.error('Failed to fetch subjects:', error)
  }
}
async function fetchTerms() {
  try {
    const data = await getTerms()
    terms.value = Array.isArray(data) ? data : []
  } catch (error) {
    console.error('Failed to fetch terms:', error)
  }
}
async function fetchStories() {
  try {
    const data = await getStories()
    stories.value = Array.isArray(data) ? data : []
  } catch (error) {
    console.error('Failed to fetch stories:', error)
  }
}

async function fetchTasks(filterParams = null) {
  isLoading.value = true
  clearError()
  try {
    const params = filterParams || {
      student_id: filterPanel.filters.value.studentId,
      subject_id: filterPanel.filters.value.subjectId,
      term_id: filterPanel.filters.value.termId,
      story_id: filterPanel.filters.value.storyId,
    }
    const response = await getTasks(params)
    tasks.value = Array.isArray(response) ? response : []
  } catch (e) {
    setError(e?.response?.data?.detail || e?.message || t('task.messages.loadError'))
    setTimeout(clearError, 3000)
  } finally {
    isLoading.value = false
  }
}

// ─── Filter handlers ────────────────────────────────────────────────
async function onApplyFilters() {
  await fetchTasks()
}
async function onClearFilters() {
  filterPanel.clear()
  await fetchTasks({})
}
function onToggleFilterPanel() {
  filterPanel.toggleFilterPanel()
}

// Bridge filter field changes from TaskFilters (which forwards each
// v-select change as an update:* event) back into the parent's filters
// ref. We do not mutate the prop directly — TaskFilters owns the
// display, the parent owns the state.
function onUpdateStudentId(value) {
  filterPanel.filters.value.studentId = value
}
function onUpdateSubjectId(value) {
  filterPanel.filters.value.subjectId = value
}
function onUpdateTermId(value) {
  filterPanel.filters.value.termId = value
}
function onUpdateStoryId(value) {
  filterPanel.filters.value.storyId = value
}

// ─── Edit dialog open / close ───────────────────────────────────────
function openEditForTask(taskId) {
  // 列表接口已经返回编辑对话框所需的全量字段，直接复用缓存避免一次额外的请求。
  const cached = tasks.value.find((t) => t.task_id === taskId)
  if (!cached) {
    setError(t('task.messages.loadError'))
    setTimeout(clearError, 3000)
    return
  }
  editingTask.value = cached
  creatingDate.value = null
  editDialog.value = true
}
function openCreateForDate(date) {
  editingTask.value = null
  creatingDate.value = date || new Date()
  editDialog.value = true
}
function closeEditDialog() {
  editDialog.value = false
  editingTask.value = null
  creatingDate.value = null
}

function onCalendarEventClick(taskId) {
  openEditForTask(taskId)
}
function onCalendarDateClick(date) {
  openCreateForDate(date)
}
async function onCalendarEventDrop({ taskId, diffDays, revert }) {
  const task = tasks.value.find((t) => t.task_id === taskId)
  if (!task) {
    revert()
    return
  }
  const oldStart = new Date(task.start_date)
  const oldEnd = new Date(task.end_date)
  const newStart = new Date(oldStart.getTime() + diffDays * 86400000)
  const newEnd = new Date(oldEnd.getTime() + diffDays * 86400000)
  isLoading.value = true
  try {
    await updateTask(taskId, {
      start_date: newStart.toISOString(),
      end_date: newEnd.toISOString(),
    })
    await fetchTasks()
  } catch (err) {
    revert()
    setError(err?.message || t('task.messages.updateError'))
    setTimeout(clearError, 3000)
  } finally {
    isLoading.value = false
  }
}

function onTaskSaved(updatedTask) {
  if (!updatedTask?.task_id) return
  const idx = tasks.value.findIndex((t) => t.task_id === updatedTask.task_id)
  if (idx !== -1) {
    tasks.value[idx] = { ...tasks.value[idx], ...updatedTask }
  } else {
    tasks.value.push(updatedTask)
  }
}
function onTaskDeleted(deletedId) {
  const idx = tasks.value.findIndex((t) => t.task_id === deletedId)
  if (idx !== -1) tasks.value.splice(idx, 1)
}

function onOpenCarousel(imageId) {
  initialImageId.value = imageId
  imageDialog.value = true
}
function onCloseCarousel() {
  imageDialog.value = false
  initialImageId.value = null
}

// ─── Keyboard / mount ───────────────────────────────────────────────
function handleKeydown(event) {
  if (event.key !== 'Escape') return
  // 有对话框打开时 Esc 只关对话框，不退出全屏；TaskCalendar 自己处理全屏。
  if (editDialog.value || imageDialog.value) return
  // Calendar's fullscreen is internal; we don't toggle it from here.
}

onMounted(() => {
  Promise.all([fetchTasks({}), fetchStudents(), fetchSubjects(), fetchTerms(), fetchStories()])
  document.addEventListener('keydown', handleKeydown)
})
onUnmounted(() => {
  document.removeEventListener('keydown', handleKeydown)
})
</script>

<template>
  <v-container fluid class="pt-0">
    <v-row class="mb-4">
      <v-col cols="12">
        <h2>{{ t('task.title') }}</h2>
      </v-col>
    </v-row>

    <div class="d-flex task-layout">
      <TaskFilters
        :filters="filterPanel.filters.value"
        :is-filter-expanded="filterPanel.isFilterExpanded.value"
        :student-options="filterPanel.studentOptions.value"
        :subject-options="filterPanel.subjectOptions.value"
        :term-options="filterPanel.termOptions.value"
        :filtered-story-options="filterPanel.filteredStoryOptions.value"
        :loading="isLoading"
        @apply="onApplyFilters"
        @clear="onClearFilters"
        @toggle="onToggleFilterPanel"
        @update:student-id="onUpdateStudentId"
        @update:subject-id="onUpdateSubjectId"
        @update:term-id="onUpdateTermId"
        @update:story-id="onUpdateStoryId"
      />

      <TaskCalendar
        :tasks="tasks"
        :students="students"
        :subjects="subjects"
        :loading="isLoading"
        :is-filter-expanded="filterPanel.isFilterExpanded.value"
        @event-click="onCalendarEventClick"
        @date-click="onCalendarDateClick"
        @event-drop="onCalendarEventDrop"
        @toggle-filter-panel="onToggleFilterPanel"
      />
    </div>

    <TaskEditDialog
      :open="editDialog"
      :task="editingTask"
      :initial-date="creatingDate"
      :students="students"
      :subjects="subjects"
      :terms="terms"
      :stories="stories"
      :img="img"
      @close="closeEditDialog"
      @saved="onTaskSaved"
      @deleted="onTaskDeleted"
      @open-carousel="onOpenCarousel"
    />

    <TaskImageCarousel
      :img="img"
      :open="imageDialog"
      :initial-image-id="initialImageId"
      @close="onCloseCarousel"
    />
  </v-container>
</template>

<style scoped>
.task-layout {
  position: relative;
}

@media (max-width: 960px) {
  .task-layout {
    flex-direction: column;
  }
}
</style>
