<script lang="ts" setup>
/**
 * 工作台「日程待办」widget：放在快捷入口同一行右侧
 * - 露出未来 7 天（含今天）的日历待办：紧凑列表自适应高度，超出内部滚动
 * - 勾选即完成；点条目弹编辑弹窗（复用日历模块 TodoModal）；头部可新建/跳转日程日历页
 * - 无待办时收缩为小尺寸空态，不占工作台空间
 */
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';

import { useVbenModal } from '@vben/common-ui';
import { IconifyIcon as VbenIcon } from '@vben/icons';

import { Checkbox, Spin } from 'ant-design-vue';
import dayjs from 'dayjs';

import { getCalendarTodoList, toggleCalendarTodoDone } from '#/views/dashboard/calendar/api';
import TodoModalComp from '#/views/dashboard/calendar/components/todo-modal.vue';

interface Props {
  title: string;
}
defineProps<Props>();

const router = useRouter();
const loading = ref(false);
/** 未来 7 天（含今天）的待办，未完成在前、时间升序 */
const list = ref<any[]>([]);

/** 待办新建/编辑弹窗：与日程日历页共用同一组件 */
const [TodoFormModal, todoModalApi] = useVbenModal({
  connectedComponent: TodoModalComp,
});

/** 未完成数：标题角标 */
const undoneCount = computed(
  () => list.value.filter((t) => Number(t.is_done) !== 1).length,
);

/**
 * 拉取今天 0 点起 7 天内的待办
 * 排序策略：未完成优先（工作台关注「还要做什么」），组内按时间升序
 */
async function fetchTodos() {
  loading.value = true;
  try {
    const start = dayjs().startOf('day');
    const end = dayjs().add(6, 'day').endOf('day');
    const res = await getCalendarTodoList({
      start_time: start.unix(),
      end_time: end.unix(),
    });
    list.value = (Array.isArray(res) ? res : []).sort((a: any, b: any) => {
      const doneDiff = Number(a.is_done) - Number(b.is_done);
      if (doneDiff !== 0) return doneDiff;
      return Number(a.todo_time) - Number(b.todo_time);
    });
  } catch {
    list.value = [];
  } finally {
    loading.value = false;
  }
}

/** 行日期标签：今天/明天，更远的显示 M/D 周X */
function dayLabel(todo: any) {
  const t = dayjs.unix(Number(todo.todo_time)).startOf('day');
  const diff = t.diff(dayjs().startOf('day'), 'day');
  if (diff === 0) return '今天';
  if (diff === 1) return '明天';
  const weeks = ['日', '一', '二', '三', '四', '五', '六'];
  return `${t.format('M/D')} 周${weeks[t.day()]}`;
}

/** 行时间标签：00:00 视为全天 */
function timeLabel(todo: any) {
  const t = dayjs.unix(Number(todo.todo_time));
  return t.format('HH:mm') === '00:00' ? '全天' : t.format('HH:mm');
}

/** 勾选切换完成状态：本地同步字段避免整列表重拉闪烁 */
async function onToggle(todo: any, checked: boolean) {
  await toggleCalendarTodoDone({ id: todo.id, is_done: checked ? 1 : 0 });
  todo.is_done = checked ? 1 : 0;
}

/** 新建待办：默认今天，保存后重拉列表 */
function createTodo() {
  todoModalApi
    .setData({
      update: false,
      defaultDate: dayjs().format('YYYY-MM-DD'),
      onSaved: fetchTodos,
    })
    .open();
}

/** 编辑待办 */
function editTodo(todo: any) {
  todoModalApi.setData({ update: true, values: todo, onSaved: fetchTodos }).open();
}

/** 跳转完整日程日历页（xk_menu path=/calendar） */
function goCalendar() {
  router.push('/calendar').catch(() => {});
}

onMounted(fetchTodos);
</script>
<template>
  <div class="calendar-todo-widget">
    <div class="ctw-head">
      <span class="ctw-title">
        <VbenIcon class="ctw-title-icon" icon="lucide:calendar-check-2" />
        {{ title }}
        <em v-if="undoneCount > 0" class="ctw-count">{{ undoneCount }}</em>
      </span>
      <div class="ctw-actions">
        <button class="ctw-btn" @click="createTodo">
          <VbenIcon icon="lucide:plus" />新建
        </button>
        <button class="ctw-btn ghost" title="打开日程日历" @click="goCalendar">
          <VbenIcon icon="lucide:calendar-days" />日历
        </button>
      </div>
    </div>
    <Spin :spinning="loading">
      <!-- 有待办：紧凑列表，超出内部滚动（列表高度自适应内容） -->
      <div v-if="list.length > 0" class="ctw-list">
        <div
          v-for="todo in list"
          :key="todo.id"
          class="ctw-item"
          :class="{ done: Number(todo.is_done) === 1 }"
        >
          <Checkbox
            class="ctw-item-check"
            :checked="Number(todo.is_done) === 1"
            @change="(e: any) => onToggle(todo, e.target.checked)"
          />
          <div class="ctw-item-main" @click="editTodo(todo)">
            <div class="ctw-item-title">{{ todo.title }}</div>
            <div class="ctw-item-meta">
              <span class="ctw-item-day" :class="{ today: dayLabel(todo) === '今天' }">
                {{ dayLabel(todo) }}
              </span>
              <span class="ctw-item-time">
                <VbenIcon icon="lucide:clock" />{{ timeLabel(todo) }}
              </span>
              <span v-if="Number(todo.remind_status) === 2" class="ctw-item-fail">提醒失败</span>
            </div>
          </div>
          <VbenIcon class="ctw-item-arrow" icon="lucide:chevron-right" />
        </div>
      </div>
      <!-- 空态：小尺寸不占空间 -->
      <div v-else class="ctw-empty">
        <VbenIcon class="ctw-empty-icon" icon="lucide:list-checks" />
        <span class="ctw-empty-text">近 7 天暂无待办</span>
        <button class="ctw-btn" @click="createTodo">新建一条</button>
      </div>
    </Spin>
    <TodoFormModal />
  </div>
</template>
<style lang="scss" scoped>
/* 卡片外壳：与工作台其他 widget 一致（发丝线 + 12px 圆角，不用左侧色条） */
.calendar-todo-widget {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 18px 20px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border) / 70%);
  border-radius: 12px;
}

/* 2/8 分时列宽较窄：允许标题与按钮组换行，避免挤压溢出 */
.ctw-head {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.ctw-title {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  font-size: 15px;
  font-weight: 600;
  color: hsl(var(--foreground));
}

.ctw-title-icon {
  font-size: 16px;
  color: hsl(var(--primary));
}

.ctw-count {
  padding: 0 7px;
  font-size: 11px;
  font-style: normal;
  font-weight: 600;
  line-height: 18px;
  color: hsl(var(--primary));
  background: hsl(var(--primary) / 12%);
  border-radius: 999px;
}

.ctw-actions {
  display: flex;
  gap: 6px;
  align-items: center;
}

.ctw-btn {
  display: inline-flex;
  gap: 3px;
  align-items: center;
  padding: 4px 10px;
  font-size: 12px;
  color: hsl(var(--primary));
  cursor: pointer;
  background: hsl(var(--primary) / 10%);
  border: none;
  border-radius: 999px;
  transition: background-color 0.2s;

  &:hover {
    background: hsl(var(--primary) / 18%);
  }

  &.ghost {
    color: hsl(var(--muted-foreground));
    background: hsl(var(--muted) / 50%);

    &:hover {
      color: hsl(var(--foreground));
      background: hsl(var(--muted) / 80%);
    }
  }
}

/* Spin 包裹层吃掉卡内剩余高度：与日历等高排布时列表在卡内弹性滚动（等高的关键） */
.calendar-todo-widget :deep(.ant-spin-nested-loading) {
  flex: 1;
  min-height: 0;
}

.calendar-todo-widget :deep(.ant-spin-nested-loading .ant-spin-container) {
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* 列表：吃满剩余高度，超出内部滚动（行高由同行的日历决定） */
.ctw-list {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  padding-right: 4px;
  overflow-y: auto;
}

/* 窄屏堆叠后行高不再受日历约束，限高防止长列表把工作台拉得过长 */
@media (max-width: 1024px) {
  .ctw-list {
    max-height: 320px;
  }
}

.ctw-item {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  padding: 8px 10px;
  background: hsl(var(--muted) / 30%);
  border: 1px solid transparent;
  border-radius: 10px;
  transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;

  &:hover {
    background: hsl(var(--muted) / 45%);
    border-color: hsl(var(--primary) / 35%);
    box-shadow: 0 0 6px hsl(var(--primary) / 15%);

    .ctw-item-arrow {
      opacity: 1;
    }
  }

  &.done {
    .ctw-item-title {
      color: hsl(var(--muted-foreground));
      text-decoration: line-through;
    }
  }
}

.ctw-item-check {
  margin-top: 1px;
}

.ctw-item-main {
  flex: 1;
  min-width: 0;
  cursor: pointer;
}

.ctw-item-title {
  overflow: hidden;
  font-size: 13px;
  font-weight: 500;
  color: hsl(var(--foreground));
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ctw-item-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 3px;
  font-size: 11px;
  color: hsl(var(--muted-foreground));
}

/* 日期标签：今天用主色强调，一眼区分紧急程度 */
.ctw-item-day {
  padding: 0 6px;
  font-weight: 600;
  line-height: 16px;
  background: hsl(var(--muted) / 60%);
  border-radius: 4px;

  &.today {
    color: hsl(var(--primary));
    background: hsl(var(--primary) / 12%);
  }
}

.ctw-item-time {
  display: inline-flex;
  gap: 3px;
  align-items: center;
}

.ctw-item-fail {
  color: hsl(var(--destructive));
}

.ctw-item-arrow {
  flex-shrink: 0;
  margin-top: 3px;
  font-size: 14px;
  color: hsl(var(--muted-foreground));
  opacity: 0;
  transition: opacity 0.2s;
}

/* 空态：吃满剩余高度垂直居中（与日历等高时不显得头重脚轻） */
.ctw-empty {
  display: flex;
  flex: 1;
  gap: 10px;
  align-items: center;
  justify-content: center;
  padding: 22px 0;
}

.ctw-empty-icon {
  font-size: 22px;
  color: hsl(var(--muted-foreground) / 50%);
}

.ctw-empty-text {
  font-size: 13px;
  color: hsl(var(--muted-foreground));
}
</style>
