<template>
  <v-container fluid class="pa-6">
    <v-card elevation="0" border rounded="lg">
      <v-card-title class="d-flex align-center text-h6">
        推送调度
        <v-spacer />
        <v-btn color="primary" variant="flat" size="small" prepend-icon="mdi-plus" @click="openEditor(null)">新建调度</v-btn>
      </v-card-title>

      <v-data-table-server
        :items="schedules"
        :headers="headers"
        :items-length="totalItems"
        :loading="loading"
        :page="page"
        :items-per-page="itemsPerPage"
        hover
        density="comfortable"
        @update:page="onPageChange"
        @update:items-per-page="onItemsPerPageChange"
      >
        <template #item.enabled="{ item }">
          <v-switch
            v-model="item.enabled"
            color="primary"
            density="compact"
            hide-details
            :loading="togglingId === item.id"
            @update:model-value="toggleEnabled(item)"
          />
        </template>

        <template #item.cron_expr="{ item }">
          <v-chip size="small" variant="tonal" label prepend-icon="mdi-clock-outline">
            {{ item.cron_expr || '—' }}
          </v-chip>
        </template>

        <template #item.server_count="{ item }">
          <span class="text-medium-emphasis">{{ serverIdCount(item.server_ids) }} 台</span>
        </template>

        <template #item.last_run_at="{ item }">
          <span class="text-caption text-medium-emphasis">{{ item.last_run_at || '从未运行' }}</span>
        </template>

        <template #item.next_run="{ item }">
          <span class="text-caption text-medium-emphasis">{{ item.next_run || '—' }}</span>
        </template>

        <template #item.actions="{ item }">
          <v-btn variant="text" size="x-small" density="compact" @click="openEditor(item)">编辑</v-btn>
          <v-btn variant="text" size="x-small" density="compact" :loading="runningId === item.id" @click="runNow(item)">立即执行</v-btn>
          <v-btn variant="text" size="x-small" color="error" density="compact" @click="confirmDelete(item)">删除</v-btn>
        </template>
        <template #no-data>
          <div class="text-center text-medium-emphasis py-6">暂无计划任务</div>
        </template>
      </v-data-table-server>
    </v-card>

    <!-- Editor Dialog -->
    <v-dialog v-model="showEditor" max-width="600">
      <v-card border>
        <v-card-title>{{ editingSchedule ? '编辑调度' : '新建调度' }}</v-card-title>
        <v-card-text>
          <v-text-field v-model="form.name" label="调度名称" variant="outlined" density="compact" class="mb-2" />
          <v-text-field v-model="form.cron" label="Cron 表达式" variant="outlined" density="compact" hint="例如: */30 * * * *" persistent-hint class="mb-2" />
          <v-text-field v-model="form.source_path" label="推送源路径" variant="outlined" density="compact" class="mb-2" />
          <v-text-field v-model="form.target_path" label="目标路径" variant="outlined" density="compact" class="mb-2" />
          <v-select
            v-model="form.server_ids"
            :items="serverList"
            item-title="name"
            item-value="id"
            label="目标服务器"
            variant="outlined"
            density="compact"
            multiple
            chips
            class="mb-2"
          />
          <v-switch v-model="form.enabled" label="启用" color="primary" density="compact" hide-details />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showEditor = false">取消</v-btn>
          <v-btn color="primary" variant="flat" @click="saveSchedule" :loading="saving">保存</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Delete Confirm -->
    <v-dialog v-model="showDelete" max-width="400">
      <v-card border>
        <v-card-title>确认删除</v-card-title>
        <v-card-text>确定要删除调度 <strong>{{ deletingSchedule?.name }}</strong> 吗？</v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showDelete = false">取消</v-btn>
          <v-btn color="error" variant="flat" @click="doDelete">删除</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-container>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { http } from '@/api'
import { useServerList } from '@/composables/useServerList'
import { useSnackbar } from '@/composables/useSnackbar'
import type { ScheduleItem } from '@/types/api'

const snackbar = useSnackbar()
const { servers: serverList, loadServers } = useServerList()

// ── State ──
const loading = ref(false)
const togglingId = ref<number | null>(null)
const runningId = ref<number | null>(null)
const schedules = ref<ScheduleItem[]>([])

// Pagination
const page = ref(1)
const totalItems = ref(0)
const itemsPerPage = ref(20)

// Editor
const showEditor = ref(false)
const editingSchedule = ref<ScheduleItem | null>(null)
const saving = ref(false)
const form = ref({
  name: '', cron: '', source_path: '', target_path: '',
  server_ids: [] as number[], enabled: true,
})

// Delete
const showDelete = ref(false)
const deletingSchedule = ref<ScheduleItem | null>(null)

const headers = [
  { title: '名称', key: 'name' },
  { title: 'Cron', key: 'cron_expr', width: 160 },
  { title: '源路径', key: 'source_path' },
  { title: '目标路径', key: 'target_path' },
  { title: '服务器', key: 'server_count', width: 80 },
  { title: '上次运行', key: 'last_run_at', width: 140 },
  { title: '下次运行', key: 'next_run', width: 140 },
  { title: '启用', key: 'enabled', width: 80 },
  { title: '操作', key: 'actions', width: 200, align: 'end' as const },
]

function parseServerIds(raw: unknown): number[] {
  if (Array.isArray(raw)) return raw.map((x) => Number(x)).filter((n) => !Number.isNaN(n))
  if (typeof raw === 'string' && raw.trim()) {
    try {
      const parsed = JSON.parse(raw)
      if (Array.isArray(parsed)) return parsed.map((x) => Number(x)).filter((n) => !Number.isNaN(n))
    } catch { /* ignore */ }
  }
  return []
}

function serverIdCount(raw: unknown): number {
  return parseServerIds(raw).length
}

function normalizeSchedule(row: ScheduleItem): ScheduleItem {
  return { ...row, server_ids: parseServerIds(row.server_ids) }
}

function buildSchedulePayload() {
  const ids = form.value.server_ids
  if (!form.value.name.trim()) throw new Error('请填写调度名称')
  if (!form.value.cron.trim()) throw new Error('请填写 Cron 表达式')
  if (!/^[\d\s*/,\-]+$/.test(form.value.cron.trim())) throw new Error('Cron 表达式格式不正确')
  if (!ids.length) throw new Error('请至少选择一台服务器')
  if (!form.value.source_path.trim()) throw new Error('请填写推送源路径')
  return {
    name: form.value.name.trim(),
    cron_expr: form.value.cron.trim(),
    source_path: form.value.source_path.trim(),
    server_ids: JSON.stringify(ids),
    run_mode: 'cron' as const,
    schedule_type: 'push' as const,
    enabled: form.value.enabled,
    sync_mode: 'incremental',
  }
}

function onPageChange(p: number) {
  page.value = p
  loadSchedules()
}

function onItemsPerPageChange(n: number) {
  itemsPerPage.value = n
  page.value = 1
  loadSchedules()
}

// ── Data loading ──
async function loadSchedules() {
  loading.value = true
  try {
    const res = await http.getList<ScheduleItem>('/schedules/')
    const all = (res.items || []).map(normalizeSchedule)
    totalItems.value = all.length
    const start = (page.value - 1) * itemsPerPage.value
    schedules.value = all.slice(start, start + itemsPerPage.value)
  } catch (e: unknown) {
    schedules.value = []
    totalItems.value = 0
    snackbar(e instanceof Error ? e.message : '加载调度列表失败', 'error')
  }
  finally { loading.value = false }
}

// ── Actions ──
function openEditor(schedule: ScheduleItem | null) {
  editingSchedule.value = schedule
  if (schedule) {
    form.value = {
      name: schedule.name, cron: schedule.cron_expr || '', source_path: schedule.source_path || '',
      target_path: schedule.target_path || '', server_ids: parseServerIds(schedule.server_ids),
      enabled: schedule.enabled,
    }
  } else {
    form.value = { name: '', cron: '', source_path: '', target_path: '', server_ids: [], enabled: true }
  }
  showEditor.value = true
}

async function saveSchedule() {
  saving.value = true
  try {
    const payload = buildSchedulePayload()
    if (editingSchedule.value) await http.put(`/schedules/${editingSchedule.value.id}`, payload)
    else await http.post('/schedules/', payload)
    showEditor.value = false
    loadSchedules()
    snackbar('保存成功')
  } catch (e: any) { snackbar(e.message || '保存失败', 'error') }
  finally { saving.value = false }
}

async function toggleEnabled(item: ScheduleItem) {
  togglingId.value = item.id
  try {
    await http.put(`/schedules/${item.id}`, { enabled: item.enabled })
  } catch (e: any) {
    item.enabled = !item.enabled
    snackbar(e.message || '操作失败', 'error')
  } finally {
    togglingId.value = null
  }
}

async function runNow(item: ScheduleItem) {
  runningId.value = item.id
  try {
    await http.post('/sync/files', {
      source_path: item.source_path,
      target_path: item.target_path || '/tmp',
      server_ids: parseServerIds(item.server_ids),
    })
    snackbar('已触发推送')
  } catch (e: any) { snackbar(e.message || '执行失败', 'error') }
  finally {
    runningId.value = null
  }
}

function confirmDelete(item: ScheduleItem) {
  deletingSchedule.value = item
  showDelete.value = true
}

async function doDelete() {
  if (!deletingSchedule.value) return
  try {
    await http.delete(`/schedules/${deletingSchedule.value.id}`)
    showDelete.value = false
    loadSchedules()
    snackbar('已删除')
  } catch (e: any) { snackbar(e.message || '删除失败', 'error') }
}


onMounted(() => {
  loadSchedules()
  loadServers()
})
</script>
