<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { Tooltip, Button } from 'ant-design-vue';
import { VbenIcon } from '@vben/common-ui';
import dayjs from 'dayjs';
import { getLoginCountByMonthApi } from '#/api/core/log';
import type { LoginCountApi } from '#/api/core/log';

const props = withDefaults(
  defineProps<{
    title?: string;
    appId: number;
    uid: number;
  }>(),
  {
    title: '登录热力图',
  },
);

const currentMonth = ref(dayjs().startOf('month'));
const monthData = ref<LoginCountApi.LoginDailyCount[]>([]);
const totalCount = ref(0);
const loading = ref(false);
const collapsed = ref(true);

async function fetchData() {
  if (!props.uid) return;
  loading.value = true;
  try {
    const res = await getLoginCountByMonthApi({
      Appid: props.appId,
      Id: props.uid,
      month: currentMonth.value.format('YYYY-MM'),
    });
    monthData.value = res.data || [];
    totalCount.value = res.total || 0;
  } finally {
    loading.value = false;
  }
}

// 月份变化或 uid/appId 变化时重新请求
watch(
  () => [currentMonth.value, props.appId, props.uid] as const,
  () => fetchData(),
  { immediate: true },
);

function prevMonth() {
  currentMonth.value = currentMonth.value.subtract(1, 'month');
}

function nextMonth() {
  currentMonth.value = currentMonth.value.add(1, 'month');
}

function goToday() {
  currentMonth.value = dayjs().startOf('month');
}

function toggleCollapsed() {
  collapsed.value = !collapsed.value;
}

const monthLabel = computed(() => currentMonth.value.format('YYYY年M月'));

// 颜色等级（按登录次数）
function getColor(count: number): string {
  if (count <= 0) return 'var(--heatmap-l0)';
  if (count === 1) return 'var(--heatmap-l1)';
  if (count <= 3) return 'var(--heatmap-l2)';
  if (count <= 5) return 'var(--heatmap-l3)';
  return 'var(--heatmap-l4)';
}

function getLevelText(count: number): string {
  if (count <= 0) return '未登录';
  return `${count}次`;
}

function getCellTextColor(count: number): string {
  // 浅色格子使用深色文字，深色格子使用浅色文字，提升深色主题下可读性
  if (count <= 0) return 'hsl(var(--foreground))';
  if (count <= 3) return 'rgba(0, 0, 0, 0.82)';
  return 'rgba(255, 255, 255, 0.92)';
}

function getCellSubTextColor(count: number): string {
  if (count <= 0) return 'hsl(var(--muted-foreground))';
  return '#ff4d4f';
}

const weekDayLabels = ['一', '二', '三', '四', '五', '六', '日'];

// 按月构建周行数据
const weeks = computed(() => {
  const dataMap = new Map<string, number>();
  for (const item of monthData.value) {
    dataMap.set(item.date, item.count);
  }

  const monthStart = currentMonth.value;
  const monthEnd = currentMonth.value.endOf('month');

  // 找到本月第一天所在周的周一
  const startDay = monthStart.day(); // 0=Sun, 1=Mon ...
  let cursor = monthStart.subtract((startDay + 6) % 7, 'day');

  const result: { date: string; day: number; value: number; inMonth: boolean }[][] = [];

  while (cursor.isBefore(monthEnd) || cursor.isSame(monthEnd, 'day')) {
    const week: { date: string; day: number; value: number; inMonth: boolean }[] = [];
    for (let i = 0; i < 7; i++) {
      const dateStr = cursor.format('YYYY-MM-DD');
      const inMonth = cursor.month() === monthStart.month() && cursor.year() === monthStart.year();
      week.push({
        date: dateStr,
        day: cursor.date(),
        value: dataMap.get(dateStr) ?? 0,
        inMonth,
      });
      cursor = cursor.add(1, 'day');
    }
    result.push(week);
  }

  return result;
});

// 当月统计
const stats = computed(() => {
  let totalDays = 0;
  let totalCount = 0;
  let maxCount = 0;
  for (const item of monthData.value) {
    if (item.count > 0) {
      totalDays++;
      totalCount += item.count;
      if (item.count > maxCount) maxCount = item.count;
    }
  }
  return { totalDays, totalCount, maxCount };
});
</script>

<template>
  <div class="heatmap-container">
    <!-- 头部：标题 + 月份切换 -->
    <div class="heatmap-header">
      <button class="heatmap-title-wrap" type="button" @click="toggleCollapsed">
        <VbenIcon :icon="collapsed ? 'mdi:chevron-right' : 'mdi:chevron-down'" />
        <span class="heatmap-title">{{ title }}</span>
      </button>
      <div v-show="!collapsed" class="heatmap-nav">
        <Button size="small" @click="prevMonth"><VbenIcon icon="mdi:chevron-left" /></Button>
        <span class="heatmap-month-label">{{ monthLabel }}</span>
        <Button size="small" @click="nextMonth"><VbenIcon icon="mdi:chevron-right" /></Button>
        <Button size="small" type="link" @click="goToday">今天</Button>
      </div>
    </div>

    <div v-show="!collapsed">
      <!-- 统计 -->
      <div class="heatmap-stats">
        本月登录 <b>{{ stats.totalDays }}</b> 天，
        累计 <b>{{ stats.totalCount }}</b> 次，
        单日最多 <b>{{ getLevelText(stats.maxCount) }}</b>
      </div>

      <!-- 日历表格：一周一行 -->
      <table class="heatmap-table">
        <thead>
          <tr>
            <th v-for="label in weekDayLabels" :key="label" class="heatmap-th">{{ label }}</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(week, wi) in weeks" :key="wi">
            <td v-for="(day, di) in week" :key="di" class="heatmap-td">
              <Tooltip v-if="day.inMonth" :title="`${day.date}：${getLevelText(day.value)}`">
                <div
                  class="heatmap-day"
                  :style="{
                    backgroundColor: getColor(day.value),
                    '--heatmap-cell-text': getCellTextColor(day.value),
                    '--heatmap-cell-subtext': getCellSubTextColor(day.value),
                  }"
                >
                  <span class="heatmap-day-num">{{ day.day }}</span>
                  <span v-if="day.value > 0" class="heatmap-day-text">{{ getLevelText(day.value) }}</span>
                </div>
              </Tooltip>
              <div v-else class="heatmap-day heatmap-day-outside">
                <span class="heatmap-day-num-outside">{{ day.day }}</span>
              </div>
            </td>
          </tr>
        </tbody>
      </table>

      <!-- 图例 -->
      <div class="heatmap-legend">
        <span class="heatmap-legend-text">少</span>
        <div class="heatmap-legend-cell" style="background-color: var(--heatmap-l0)" />
        <div class="heatmap-legend-cell" style="background-color: var(--heatmap-l1)" />
        <div class="heatmap-legend-cell" style="background-color: var(--heatmap-l2)" />
        <div class="heatmap-legend-cell" style="background-color: var(--heatmap-l3)" />
        <div class="heatmap-legend-cell" style="background-color: var(--heatmap-l4)" />
        <span class="heatmap-legend-text">多</span>
      </div>
    </div>
  </div>
</template>

<style scoped>
.heatmap-container {
  --heatmap-l0: hsl(var(--muted));
  --heatmap-l1: #9be9a8;
  --heatmap-l2: #40c463;
  --heatmap-l3: #30a14e;
  --heatmap-l4: #216e39;
  background: hsl(var(--card));
  border-radius: 8px;
  padding: 16px;
  border: 1px solid hsl(var(--border));
}

:global(.dark) .heatmap-container {
  --heatmap-l0: hsl(var(--muted));
  --heatmap-l1: #1f6f43;
  --heatmap-l2: #238d50;
  --heatmap-l3: #2db35f;
  --heatmap-l4: #46d877;
}

.heatmap-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  flex-wrap: wrap;
  gap: 8px;
}

.heatmap-title {
  font-size: 16px;
  font-weight: 600;
  color: hsl(var(--foreground));
}

.heatmap-title-wrap {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  color: hsl(var(--foreground));
}

.heatmap-title-wrap:hover {
  opacity: 0.85;
}

.heatmap-nav {
  display: flex;
  align-items: center;
  gap: 8px;
}

.heatmap-month-label {
  font-size: 15px;
  font-weight: 500;
  color: hsl(var(--foreground));
  min-width: 90px;
  text-align: center;
}

.heatmap-stats {
  font-size: 13px;
  color: hsl(var(--muted-foreground));
  margin-bottom: 12px;
}

.heatmap-stats b {
  color: hsl(var(--foreground));
}

.heatmap-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 4px;
  table-layout: fixed;
}

.heatmap-th {
  font-size: 12px;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
  text-align: center;
  padding-bottom: 4px;
}

.heatmap-td {
  padding: 0;
  vertical-align: top;
}

.heatmap-day {
  border-radius: 6px;
  padding: 6px;
  min-height: 54px;
  cursor: pointer;
  transition: box-shadow 0.2s;
  display: flex;
  flex-direction: column;
}

.heatmap-day:hover {
  box-shadow: 0 0 0 2px hsl(var(--ring) / 0.3);
}

.heatmap-day-num {
  font-size: 13px;
  font-weight: 600;
  color: var(--heatmap-cell-text, hsl(var(--foreground)));
  line-height: 1;
}

.heatmap-day-text {
  font-size: 11px;
  color: var(--heatmap-cell-subtext, hsl(var(--muted-foreground)));
  margin-top: auto;
  line-height: 1;
}

.heatmap-day-outside {
  background-color: transparent !important;
  cursor: default;
}

.heatmap-day-outside:hover {
  box-shadow: none;
}

.heatmap-day-num-outside {
  font-size: 13px;
  color: hsl(var(--muted-foreground) / 0.45);
  line-height: 1;
}

.heatmap-legend {
  display: flex;
  align-items: center;
  gap: 4px;
  justify-content: flex-end;
  margin-top: 10px;
}

.heatmap-legend-text {
  font-size: 11px;
  color: hsl(var(--muted-foreground));
  margin: 0 2px;
}

.heatmap-legend-cell {
  width: 14px;
  height: 14px;
  border-radius: 3px;
}
</style>
