<script lang="ts" setup>
/**
 * 班次模板管理弹窗（店级通用 + 医生专属两档）
 * 诊所把常用班次（全天班/上午班/两班制等）保存成模板，日历排班时批量套用；
 * 「适用范围」绑定医生后成为该医生的专属模板（一医生一店仅一个），
 * 「添加医生排班」勾选优先专属时按医生自己的时段/号源写入。
 * 列表 + 内联编辑两种视图切换：模板数量少（每店 ≤20），无需分页表格，卡片列表更直观
 */
import type { ScheduleSlot, ShiftTemplate } from '../../api/schedule';

import { computed, ref } from 'vue';

import { useVbenModal } from '@vben/common-ui';

import { Button, Empty, Input, message, Popconfirm, Select, Switch, Tag } from 'ant-design-vue';

import { Icon } from '#/components/icon';

import {
  deleteShiftTemplateApi,
  getShiftTemplateListApi,
  saveShiftTemplateApi,
} from '../../api/schedule';
import SlotRowsEditor from './SlotRowsEditor.vue';

const emit = defineEmits<{ changed: [] }>();

/** 当前门店（打开时由父组件传入） */
const storeId = ref<number>(0);
const storeName = ref<string>('');
/** 店内医生列表（专属模板绑定选择用，父组件传入） */
const doctors = ref<Array<{ id: number; name: string }>>([]);
/** 模板列表 */
const list = ref<ShiftTemplate[]>([]);
/** 编辑态：null=列表视图，否则为正在编辑的模板（id=0 新增，doctor_id=0 通用 / >0 专属） */
const editing = ref<null | {
  id: number;
  doctor_id: number;
  name: string;
  slots: ScheduleSlot[];
  status: number;
}>(null);
/** 模板是否有变更（关闭时通知父组件刷新模板下拉） */
const dirty = ref(false);

/** 适用范围下拉：通用 + 店内医生（专属） */
const scopeOptions = computed(() => [
  { label: '通用（全店可套用）', value: 0 },
  ...doctors.value.map((d) => ({ label: `专属 · ${d.name}`, value: d.id })),
]);

/** 拉取模板列表 */
async function fetchList() {
  ModalApi.setState({ loading: true });
  try {
    const data = await getShiftTemplateListApi(storeId.value);
    list.value = Array.isArray(data?.list) ? data.list : [];
  } finally {
    ModalApi.setState({ loading: false });
  }
}

/** 进入新增编辑态（默认给一个全天时段起步，默认通用范围） */
function startCreate() {
  editing.value = {
    id: 0,
    doctor_id: 0,
    name: '',
    slots: [{ slot_name: '全天', start_time: '08:00', end_time: '18:00', capacity: 30 }],
    status: 1,
  };
}

/** 进入编辑态（深拷贝防止未保存时污染列表显示） */
function startEdit(row: ShiftTemplate) {
  editing.value = {
    id: row.id,
    doctor_id: Number(row.doctor_id || 0),
    name: row.name,
    slots: JSON.parse(JSON.stringify(row.slots || [])),
    status: Number(row.status),
  };
}

/** 保存模板（新增/编辑共用） */
async function handleSave() {
  if (!editing.value) return;
  if (!editing.value.name.trim()) {
    message.warning('请输入模板名称');
    return;
  }
  for (const slot of editing.value.slots) {
    if (!slot.start_time || !slot.end_time) {
      message.warning('请补全各时段的开始/结束时间');
      return;
    }
    if (!slot.capacity || slot.capacity < 1) {
      message.warning('各时段号源数量至少为 1');
      return;
    }
  }
  ModalApi.lock();
  try {
    await saveShiftTemplateApi({
      id: editing.value.id,
      store_id: storeId.value,
      doctor_id: editing.value.doctor_id,
      name: editing.value.name.trim(),
      slots: editing.value.slots,
      status: editing.value.status,
    });
    message.success('模板保存成功');
    dirty.value = true;
    editing.value = null;
    await fetchList();
  } catch {
    // 错误提示由 requestClient 统一弹出
  } finally {
    ModalApi.unlock();
  }
}

/** 启用/禁用切换（直接落库，禁用后套用下拉不再显示；doctor_id 必须回传否则会把专属绑定抹成通用） */
async function toggleStatus(row: ShiftTemplate, checked: boolean | number | string) {
  try {
    await saveShiftTemplateApi({
      id: row.id,
      store_id: storeId.value,
      doctor_id: Number(row.doctor_id || 0),
      name: row.name,
      slots: row.slots,
      status: checked ? 1 : 0,
    });
    dirty.value = true;
  } finally {
    await fetchList();
  }
}

/** 删除模板（日排班行是时段快照，删除模板不影响已排的班） */
async function handleDelete(row: ShiftTemplate) {
  await deleteShiftTemplateApi(row.id, storeId.value);
  message.success('删除成功');
  dirty.value = true;
  await fetchList();
}

const [Modal, ModalApi] = useVbenModal({
  footer: false,
  class: 'w-[560px]',
  onOpenChange(isOpen) {
    if (isOpen) {
      const data = ModalApi.getData() || {};
      storeId.value = Number(data.storeId || 0);
      storeName.value = String(data.storeName || '');
      doctors.value = Array.isArray(data.doctors) ? data.doctors : [];
      editing.value = null;
      dirty.value = false;
      fetchList();
    } else if (dirty.value) {
      emit('changed');
    }
  },
});

defineExpose({ ModalApi });
</script>

<template>
  <Modal :title="storeName ? `班次模板 - ${storeName}` : '班次模板'">
    <!-- 编辑视图 -->
    <div v-if="editing" class="tpl-edit">
      <div class="tpl-edit__item">
        <div class="tpl-edit__label">模板名称</div>
        <Input
          v-model:value="editing.name"
          :maxlength="16"
          placeholder="如：全天班 / 上午班 / 两班制"
          style="width: 260px"
        />
      </div>
      <div class="tpl-edit__item">
        <div class="tpl-edit__label">适用范围</div>
        <Select
          v-model:value="editing.doctor_id"
          :options="scopeOptions"
          option-filter-prop="label"
          show-search
          style="width: 260px"
        />
        <div class="tpl-edit__hint">
          绑定医生后成为其专属模板（一医生仅一个），「添加医生排班」勾选优先专属时按该模板的时段/号源写入
        </div>
      </div>
      <div class="tpl-edit__item">
        <div class="tpl-edit__label">班次时段</div>
        <SlotRowsEditor v-model="editing.slots" />
      </div>
      <div class="tpl-edit__actions">
        <Button @click="editing = null">返回列表</Button>
        <Button type="primary" @click="handleSave">保存模板</Button>
      </div>
    </div>

    <!-- 列表视图 -->
    <div v-else class="tpl-list">
      <div class="tpl-list__head">
        <span class="tpl-list__count">共 {{ list.length }} 个模板</span>
        <Button size="small" type="primary" @click="startCreate">
          <Icon icon="lucide:plus" />
          新增模板
        </Button>
      </div>
      <Empty v-if="list.length === 0" description="暂无班次模板，点击右上角新增" />
      <div v-for="row in list" :key="row.id" class="tpl-card">
        <div class="tpl-card__main">
          <div class="tpl-card__title">
            <span class="tpl-card__name">{{ row.name }}</span>
            <!-- 专属模板标出绑定医生，通用不加标签减少噪音 -->
            <Tag v-if="Number(row.doctor_id || 0) > 0" color="processing">
              专属 · {{ row.doctor_name || `医生#${row.doctor_id}` }}
            </Tag>
            <Tag v-if="Number(row.status) !== 1" color="default">已禁用</Tag>
          </div>
          <div class="tpl-card__slots">
            <span v-for="(slot, i) in row.slots" :key="i" class="tpl-card__slot">
              {{ slot.slot_name || `${slot.start_time}-${slot.end_time}` }}
              {{ slot.start_time }}~{{ slot.end_time }} · {{ slot.capacity }}号
            </span>
          </div>
        </div>
        <div class="tpl-card__actions">
          <Switch
            :checked="Number(row.status) === 1"
            checked-children="启用"
            size="small"
            un-checked-children="禁用"
            @change="(checked: any) => toggleStatus(row, checked)"
          />
          <Button size="small" type="link" @click="startEdit(row)">编辑</Button>
          <Popconfirm title="确定删除该模板吗？已排的班不受影响" @confirm="handleDelete(row)">
            <Button danger size="small" type="link">删除</Button>
          </Popconfirm>
        </div>
      </div>
    </div>
  </Modal>
</template>

<style scoped>
.tpl-edit {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.tpl-edit__label {
  margin-bottom: 6px;
  font-size: 13px;
  font-weight: 600;
  color: hsl(var(--foreground));
}

.tpl-edit__hint {
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.5;
  color: hsl(var(--muted-foreground));
}

.tpl-edit__actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

.tpl-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.tpl-list__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.tpl-list__count {
  font-size: 12px;
  color: hsl(var(--muted-foreground));
}

/* 模板卡片：1px 同色系边框 + 微光（禁止左侧竖色条的全局卡片规范） */
.tpl-card {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  background: hsl(var(--card, var(--background)));
  border: 1px solid hsl(var(--primary) / 30%);
  border-radius: 10px;
  box-shadow: 0 0 6px hsl(var(--primary) / 18%);
}

.tpl-card__main {
  min-width: 0;
  flex: 1;
}

.tpl-card__title {
  display: flex;
  gap: 6px;
  align-items: center;
}

.tpl-card__name {
  font-size: 14px;
  font-weight: 600;
  color: hsl(var(--foreground));
}

.tpl-card__slots {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}

.tpl-card__slot {
  padding: 2px 8px;
  font-size: 12px;
  color: hsl(var(--muted-foreground));
  background: hsl(var(--muted) / 0.35);
  border-radius: 6px;
}

.tpl-card__actions {
  display: flex;
  flex: none;
  gap: 2px;
  align-items: center;
}
</style>
