<template>
  <div class="doctor-roster p-4">
    <el-card shadow="never">
      <template #header>
        <div class="flex justify-between items-center">
          <span class="text-lg font-medium">医生排班管理</span>
          <div>
            <el-button type="success" @click="showBatchDialog">批量排班</el-button>
            <el-button @click="prevWeek">上一周</el-button>
            <el-button @click="nextWeek">下一周</el-button>
            <el-button type="primary" @click="goToday">本周</el-button>
          </div>
        </div>
      </template>

      <div class="mb-4">
        <el-form inline>
          <el-form-item label="医生">
            <el-input v-model="searchName" placeholder="请输入医生姓名" clearable style="width: 200px" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="loadData">查询</el-button>
          </el-form-item>
        </el-form>
      </div>

      <el-alert type="info" :closable="false" class="mb-4" show-icon>
        每条排班为一段连续可挂号时间；同一天可添加多段（如白班 + 夜班）。休息时段不添加出诊段即可。号源间隔默认 15 分钟；号源数填 0 表示按时段长度自动满号。
      </el-alert>

      <div class="text-center mb-4 text-gray-600">
        {{ weekText }}
      </div>

      <el-table :data="filteredTableData" border v-loading="loading">
        <el-table-column prop="doctorName" label="医生" width="120" fixed />
        <el-table-column v-for="day in weekDays" :key="day.date" :label="day.label" min-width="168">
          <template #default="{ row }">
            <div
              class="day-cell rounded border border-dashed border-gray-200 p-1 min-h-[56px] cursor-pointer hover:bg-gray-50"
              @click="openDayDialog(row, day.date)"
            >
              <template v-if="getDaySegments(row, day.date).length === 0">
                <div class="text-xs text-gray-400 text-center py-2">点击管理</div>
              </template>
              <div v-else class="space-y-1">
                <div
                  v-for="seg in getDaySegments(row, day.date)"
                  :key="seg.id"
                  class="text-xs px-1 py-0.5 rounded leading-tight"
                  :class="segmentChipClass(seg.status)"
                >
                  {{ formatSegmentLine(seg) }}
                </div>
              </div>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 某日排班列表 -->
    <el-dialog v-model="dayDialogVisible" :title="dayDialogTitle" width="720px" destroy-on-close>
      <el-table :data="dayDialogSegments" border size="small" max-height="360">
        <el-table-column label="时间" width="150">
          <template #default="{ row }">{{ row.start_time }} - {{ row.end_time }}</template>
        </el-table-column>
        <el-table-column label="班次" width="80">
          <template #default="{ row }">{{ shiftLabel(row.shift_type) }}</template>
        </el-table-column>
        <el-table-column label="状态" width="88">
          <template #default="{ row }">{{ statusText(row.status) }}</template>
        </el-table-column>
        <el-table-column label="间隔" width="72">
          <template #default="{ row }">{{ row.slot_minutes || 15 }} 分</template>
        </el-table-column>
        <el-table-column label="号源" width="72">
          <template #default="{ row }">{{ row.status === 1 ? row.quota || '不限' : '-' }}</template>
        </el-table-column>
        <el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip />
        <el-table-column label="操作" width="140" fixed="right">
          <template #default="{ row }">
            <el-button type="primary" link @click="openSegmentForm(row)">编辑</el-button>
            <el-button type="danger" link @click="removeSegment(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <template #footer>
        <el-button @click="dayDialogVisible = false">关闭</el-button>
        <el-button type="primary" @click="openSegmentForm()">添加时段</el-button>
      </template>
    </el-dialog>

    <!-- 单段排班表单 -->
    <el-dialog v-model="segmentDialogVisible" :title="segmentForm.id ? '编辑时段' : '添加时段'" width="520px" destroy-on-close>
      <el-form :model="segmentForm" label-width="110px">
        <el-form-item label="接诊时间" required>
          <div class="flex items-center gap-2 flex-wrap">
            <el-time-select
              v-model="segmentForm.start_time"
              start="00:00"
              step="00:5"
              end="23:45"
              placeholder="开始"
              style="width: 120px"
            />
            <span>至</span>
            <el-time-select
              v-model="segmentForm.end_time"
              start="00:00"
              step="00:5"
              end="23:45"
              placeholder="结束"
              style="width: 120px"
            />
          </div>
        </el-form-item>
        <el-form-item label="班次标签">
          <el-select v-model="segmentForm.shift_type" placeholder="选填" clearable style="width: 200px">
            <el-option label="白班" value="day" />
            <el-option label="夜班" value="night" />
          </el-select>
        </el-form-item>
        <el-form-item label="号源间隔(分)">
          <el-input-number v-model="segmentForm.slot_minutes" :min="5" :max="120" :step="5" />
          <span class="ml-2 text-gray-500 text-sm">默认 15</span>
        </el-form-item>
        <el-form-item label="状态">
          <el-radio-group v-model="segmentForm.status">
            <el-radio :label="1">出诊</el-radio>
            <el-radio :label="2">停诊</el-radio>
            <el-radio :label="3">休息</el-radio>
            <el-radio :label="4">请假</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="号源上限" v-if="segmentForm.status === 1">
          <el-input-number v-model="segmentForm.quota" :min="0" :max="200" />
          <div class="text-gray-500 text-xs mt-1">0 表示不限制（由时段÷间隔计算可约数）</div>
        </el-form-item>
        <el-form-item label="最大接诊" v-if="segmentForm.status === 1">
          <el-input-number v-model="segmentForm.max_patients" :min="0" :max="500" />
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="segmentForm.remark" type="textarea" :rows="2" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="segmentDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="segmentSaving" @click="saveSegment">保存</el-button>
      </template>
    </el-dialog>

    <!-- 批量排班 -->
    <el-dialog v-model="batchDialogVisible" title="批量排班" width="780px" destroy-on-close>
      <el-form :model="batchForm" label-width="100px">
        <el-form-item label="选择医生" required>
          <el-select v-model="batchForm.doctorIds" multiple placeholder="请选择医生" class="w-full" filterable>
            <el-option v-for="doctor in tableData" :key="doctor.doctorId" :label="doctor.doctorName" :value="doctor.doctorId" />
          </el-select>
        </el-form-item>

        <el-form-item label="日期范围" required>
          <el-date-picker
            v-model="batchForm.dateRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD"
            class="w-full"
          />
        </el-form-item>

        <el-form-item label="星期" required>
          <el-checkbox-group v-model="batchForm.weekdays">
            <el-checkbox :label="1">周一</el-checkbox>
            <el-checkbox :label="2">周二</el-checkbox>
            <el-checkbox :label="3">周三</el-checkbox>
            <el-checkbox :label="4">周四</el-checkbox>
            <el-checkbox :label="5">周五</el-checkbox>
            <el-checkbox :label="6">周六</el-checkbox>
            <el-checkbox :label="0">周日</el-checkbox>
          </el-checkbox-group>
        </el-form-item>

        <el-form-item label="时段模板">
          <div class="w-full space-y-2">
            <div v-for="(seg, idx) in batchForm.segments" :key="idx" class="flex flex-wrap items-center gap-2 p-2 bg-gray-50 rounded">
              <el-time-select v-model="seg.start_time" start="00:00" step="00:05" end="23:45" placeholder="开始" style="width: 110px" />
              <span>—</span>
              <el-time-select v-model="seg.end_time" start="00:00" step="00:05" end="23:45" placeholder="结束" style="width: 110px" />
              <el-select v-model="seg.shift_type" placeholder="班次" clearable style="width: 100px">
                <el-option label="白班" value="day" />
                <el-option label="夜班" value="night" />
              </el-select>
              <span class="text-sm text-gray-500">间隔</span>
              <el-input-number v-model="seg.slot_minutes" :min="5" :max="120" :step="5" style="width: 100px" />
              <span class="text-sm text-gray-500">号源0=不限</span>
              <el-input-number v-model="seg.quota" :min="0" :max="200" style="width: 100px" />
              <el-button type="danger" link @click="batchRemoveSegment(idx)" :disabled="batchForm.segments.length <= 1">删除</el-button>
            </div>
            <el-button type="primary" link @click="batchAddSegment">+ 增加一段</el-button>
            <el-button type="success" link @click="batchAddNightTemplate">+ 夜班 18:00–22:00</el-button>
          </div>
        </el-form-item>

        <el-form-item label="排班状态" required>
          <el-radio-group v-model="batchForm.status">
            <el-radio :label="1">出诊</el-radio>
            <el-radio :label="2">停诊</el-radio>
            <el-radio :label="3">休息</el-radio>
            <el-radio :label="4">请假</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="备注">
          <el-input v-model="batchForm.remark" type="textarea" :rows="2" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="batchDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleBatchSave" :loading="batchSaving">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts" name="doctorRoster">
import { ref, computed, onMounted } from 'vue'
import dayjs from 'dayjs'
import isoWeek from 'dayjs/plugin/isoWeek'
import feedback from '@/utils/feedback'
import { doctorLists, rosterLists, rosterSave, rosterDelete, rosterBatchSave } from '@/api/doctor'
import { ElMessageBox } from 'element-plus'

dayjs.extend(isoWeek)

interface RosterSegment {
  id: number
  status: number
  quota: number
  max_patients?: number
  start_time: string
  end_time: string
  shift_type?: string | null
  slot_minutes?: number
  remark?: string
  period?: string
}

interface DoctorRow {
  doctorId: number
  doctorName: string
  /** date -> segments */
  rostersByDate: Record<string, RosterSegment[]>
}

const searchName = ref('')
const currentWeekStart = ref(dayjs().startOf('isoWeek'))
const loading = ref(false)

const dayDialogVisible = ref(false)
const dayDialogDoctor = ref<DoctorRow | null>(null)
const dayDialogDate = ref('')
const dayDialogSegments = ref<RosterSegment[]>([])

const segmentDialogVisible = ref(false)
const segmentSaving = ref(false)
const segmentForm = ref({
  id: null as number | null,
  doctorId: 0,
  date: '',
  start_time: '09:00',
  end_time: '12:00',
  shift_type: '' as string,
  slot_minutes: 15,
  status: 1,
  quota: 0,
  max_patients: 0,
  remark: ''
})

const batchDialogVisible = ref(false)
const batchSaving = ref(false)

interface BatchSegTpl {
  start_time: string
  end_time: string
  shift_type: string
  slot_minutes: number
  quota: number
}

const defaultBatchSegments = (): BatchSegTpl[] => [
  { start_time: '09:00', end_time: '12:00', shift_type: 'day', slot_minutes: 15, quota: 0 },
  { start_time: '14:00', end_time: '18:00', shift_type: 'day', slot_minutes: 15, quota: 0 }
]

const batchForm = ref({
  doctorIds: [] as number[],
  dateRange: [] as string[],
  weekdays: [1, 2, 3, 4, 5] as number[],
  status: 1,
  remark: '',
  segments: defaultBatchSegments()
})

const tableData = ref<DoctorRow[]>([])

const filteredTableData = computed(() => {
  const q = searchName.value.trim()
  if (!q) return tableData.value
  return tableData.value.filter((r) => r.doctorName.includes(q))
})

const dayDialogTitle = computed(() => {
  if (!dayDialogDoctor.value || !dayDialogDate.value) return '当日排班'
  return `${dayDialogDoctor.value.doctorName} · ${dayDialogDate.value}`
})

const weekDays = computed(() => {
  const days = []
  const labels = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
  for (let i = 0; i < 7; i++) {
    const date = currentWeekStart.value.add(i, 'day')
    days.push({
      date: date.format('YYYY-MM-DD'),
      label: `${labels[i]} ${date.format('MM-DD')}`
    })
  }
  return days
})

const weekText = computed(() => {
  const start = currentWeekStart.value.format('YYYY-MM-DD')
  const end = currentWeekStart.value.add(6, 'day').format('YYYY-MM-DD')
  return `${start} 至 ${end}`
})

function statusText(s: number) {
  const m: Record<number, string> = { 1: '出诊', 2: '停诊', 3: '休息', 4: '请假' }
  return m[s] ?? String(s)
}

function shiftLabel(t?: string | null) {
  if (t === 'day') return '白班'
  if (t === 'night') return '夜班'
  return '—'
}

function segmentChipClass(status: number) {
  if (status === 1) return 'bg-emerald-50 text-emerald-800 border border-emerald-100'
  if (status === 2) return 'bg-amber-50 text-amber-900 border border-amber-100'
  if (status === 3) return 'bg-slate-100 text-slate-600 border border-slate-200'
  return 'bg-gray-100 text-gray-700 border border-gray-200'
}

function formatSegmentLine(seg: RosterSegment) {
  const t = `${seg.start_time}-${seg.end_time}`
  const sh = shiftLabel(seg.shift_type)
  const shPart = sh !== '—' ? ` ${sh}` : ''
  if (seg.status === 1) {
    const q = seg.quota > 0 ? ` 号源${seg.quota}` : ''
    return `${t}${shPart} 出诊${q}`
  }
  return `${t}${shPart} ${statusText(seg.status)}`
}

function getDaySegments(row: DoctorRow, date: string): RosterSegment[] {
  return row.rostersByDate[date] || []
}

function refreshDayDialogList() {
  if (!dayDialogDoctor.value || !dayDialogDate.value) return
  const row = tableData.value.find((r) => r.doctorId === dayDialogDoctor.value!.doctorId)
  if (!row) return
  dayDialogSegments.value = [...(row.rostersByDate[dayDialogDate.value] || [])].sort((a, b) =>
    a.start_time.localeCompare(b.start_time)
  )
}

function openDayDialog(row: DoctorRow, date: string) {
  dayDialogDoctor.value = row
  dayDialogDate.value = date
  refreshDayDialogList()
  dayDialogVisible.value = true
}

function openSegmentForm(existing?: RosterSegment) {
  if (!dayDialogDoctor.value || !dayDialogDate.value) {
    feedback.msgWarning('请先选择日期格子')
    return
  }
  if (existing) {
    segmentForm.value = {
      id: existing.id,
      doctorId: dayDialogDoctor.value.doctorId,
      date: dayDialogDate.value,
      start_time: existing.start_time || '09:00',
      end_time: existing.end_time || '12:00',
      shift_type: existing.shift_type || '',
      slot_minutes: existing.slot_minutes || 15,
      status: existing.status,
      quota: existing.quota ?? 0,
      max_patients: existing.max_patients ?? 0,
      remark: existing.remark || ''
    }
  } else {
    segmentForm.value = {
      id: null,
      doctorId: dayDialogDoctor.value.doctorId,
      date: dayDialogDate.value,
      start_time: '09:00',
      end_time: '12:00',
      shift_type: 'day',
      slot_minutes: 15,
      status: 1,
      quota: 0,
      max_patients: 0,
      remark: ''
    }
  }
  segmentDialogVisible.value = true
}

async function saveSegment() {
  const f = segmentForm.value
  if (!f.start_time || !f.end_time) {
    feedback.msgWarning('请填写接诊开始与结束时间')
    return
  }
  if (f.status === 1 && f.start_time >= f.end_time) {
    feedback.msgWarning('出诊时结束时间须晚于开始时间')
    return
  }
  if (f.start_time >= f.end_time) {
    feedback.msgWarning('结束时间须晚于开始时间')
    return
  }

  segmentSaving.value = true
  try {
    const payload: Record<string, unknown> = {
      doctor_id: f.doctorId,
      date: f.date,
      period: 'segment',
      start_time: f.start_time,
      end_time: f.end_time,
      slot_minutes: f.slot_minutes || 15,
      status: f.status,
      quota: f.status === 1 ? f.quota : 0,
      max_patients: f.status === 1 ? f.max_patients : 0,
      remark: f.remark || ''
    }
    if (f.shift_type) {
      payload.shift_type = f.shift_type
    }
    if (f.id) {
      payload.id = f.id
    }

    await rosterSave(payload)
    feedback.msgSuccess('保存成功')
    segmentDialogVisible.value = false
    await loadRosterData()
    refreshDayDialogList()
  } catch {
    feedback.msgError('保存失败')
  } finally {
    segmentSaving.value = false
  }
}

async function removeSegment(row: RosterSegment) {
  try {
    await ElMessageBox.confirm('确定删除该时段？', '提示', { type: 'warning' })
  } catch {
    return
  }
  try {
    await rosterDelete({ id: row.id })
    feedback.msgSuccess('已删除')
    await loadRosterData()
    refreshDayDialogList()
  } catch {
    feedback.msgError('删除失败')
  }
}

const loadDoctors = async () => {
  try {
    const res = await doctorLists({
      page_no: 1,
      page_size: 1000
    })
    tableData.value = (res?.lists || []).map((doctor: any) => ({
      doctorId: doctor.id,
      doctorName: doctor.name || doctor.account,
      rostersByDate: {} as Record<string, RosterSegment[]>
    }))
    await loadRosterData()
  } catch (error) {
    console.error('加载医生列表失败:', error)
    feedback.msgError('加载医生列表失败')
  }
}

const loadRosterData = async () => {
  loading.value = true
  try {
    const params = {
      start_date: currentWeekStart.value.format('YYYY-MM-DD'),
      end_date: currentWeekStart.value.add(6, 'day').format('YYYY-MM-DD')
    }
    const res = await rosterLists(params)
    const rosters = res?.lists || []

    tableData.value.forEach((doctor) => {
      doctor.rostersByDate = {}
      rosters.forEach((roster: any) => {
        if (roster.doctor_id !== doctor.doctorId) return
        const d = roster.date
        if (!doctor.rostersByDate[d]) doctor.rostersByDate[d] = []
        doctor.rostersByDate[d].push({
          id: roster.id,
          status: roster.status,
          quota: roster.quota || 0,
          max_patients: roster.max_patients,
          start_time: roster.start_time || legacyStart(roster.period),
          end_time: roster.end_time || legacyEnd(roster.period),
          shift_type: roster.shift_type,
          slot_minutes: roster.slot_minutes ?? 15,
          remark: roster.remark,
          period: roster.period
        })
      })
    })
    refreshDayDialogList()
  } catch (error) {
    console.error('加载排班数据失败:', error)
    feedback.msgError('加载排班数据失败')
  } finally {
    loading.value = false
  }
}

function legacyStart(period: string) {
  if (period === 'morning') return '09:00'
  if (period === 'afternoon') return '14:00'
  if (period === 'night') return '18:00'
  return '09:00'
}

function legacyEnd(period: string) {
  if (period === 'morning') return '12:00'
  if (period === 'afternoon') return '18:00'
  if (period === 'night') return '22:00'
  return '12:00'
}

const loadData = () => {
  loadRosterData()
}

const prevWeek = () => {
  currentWeekStart.value = currentWeekStart.value.subtract(1, 'week')
  loadRosterData()
}

const nextWeek = () => {
  currentWeekStart.value = currentWeekStart.value.add(1, 'week')
  loadRosterData()
}

const goToday = () => {
  currentWeekStart.value = dayjs().startOf('isoWeek')
  loadRosterData()
}

const showBatchDialog = () => {
  batchForm.value = {
    doctorIds: [],
    dateRange: [],
    weekdays: [1, 2, 3, 4, 5],
    status: 1,
    remark: '',
    segments: defaultBatchSegments()
  }
  batchDialogVisible.value = true
}

const batchAddSegment = () => {
  batchForm.value.segments.push({
    start_time: '09:00',
    end_time: '12:00',
    shift_type: 'day',
    slot_minutes: 15,
    quota: 0
  })
}

const batchAddNightTemplate = () => {
  batchForm.value.segments.push({
    start_time: '18:00',
    end_time: '22:00',
    shift_type: 'night',
    slot_minutes: 15,
    quota: 0
  })
}

const batchRemoveSegment = (idx: number) => {
  if (batchForm.value.segments.length <= 1) return
  batchForm.value.segments.splice(idx, 1)
}

const handleBatchSave = async () => {
  if (batchForm.value.doctorIds.length === 0) {
    feedback.msgWarning('请选择医生')
    return
  }
  if (!batchForm.value.dateRange || batchForm.value.dateRange.length !== 2) {
    feedback.msgWarning('请选择日期范围')
    return
  }
  if (batchForm.value.weekdays.length === 0) {
    feedback.msgWarning('请选择星期')
    return
  }
  for (const seg of batchForm.value.segments) {
    if (!seg.start_time || !seg.end_time) {
      feedback.msgWarning('请完善时段模板的开始与结束时间')
      return
    }
    if (seg.start_time >= seg.end_time) {
      feedback.msgWarning('时段模板中结束时间须晚于开始时间')
      return
    }
  }

  batchSaving.value = true
  try {
    const rosters: any[] = []
    const startDate = dayjs(batchForm.value.dateRange[0])
    const endDate = dayjs(batchForm.value.dateRange[1])
    let currentDate = startDate
    while (currentDate.isBefore(endDate) || currentDate.isSame(endDate, 'day')) {
      const weekday = currentDate.day()
      if (batchForm.value.weekdays.includes(weekday)) {
        batchForm.value.doctorIds.forEach((doctorId) => {
          batchForm.value.segments.forEach((seg) => {
            const row: any = {
              doctor_id: doctorId,
              date: currentDate.format('YYYY-MM-DD'),
              period: 'segment',
              start_time: seg.start_time,
              end_time: seg.end_time,
              slot_minutes: seg.slot_minutes || 15,
              status: batchForm.value.status,
              quota: batchForm.value.status === 1 ? seg.quota : 0,
              max_patients: 0,
              remark: batchForm.value.remark
            }
            if (seg.shift_type) {
              row.shift_type = seg.shift_type
            }
            rosters.push(row)
          })
        })
      }
      currentDate = currentDate.add(1, 'day')
    }

    if (rosters.length === 0) {
      feedback.msgWarning('没有符合条件的排班数据')
      return
    }

    await rosterBatchSave({ rosters })
    feedback.msgSuccess(`批量保存成功！共处理 ${rosters.length} 条记录`)
    batchDialogVisible.value = false
    await loadRosterData()
  } catch (error) {
    console.error('批量保存失败:', error)
    feedback.msgError('批量保存失败')
  } finally {
    batchSaving.value = false
  }
}

onMounted(() => {
  loadDoctors()
})
</script>

<style scoped>
.doctor-roster {
  min-height: 100vh;
}
</style>
