<template>
  <div class="heatmap-card">
    <div class="grid-row">
      <!-- Weekday Labels (Fixed Left) -->
      <div class="weekday-col-fixed">
        <div class="weekday-label">二</div>
        <div class="weekday-label">四</div>
        <div class="weekday-label">六</div>
      </div>
      
      <!-- Scrollable Heatmap Area -->
      <div ref="scrollContainer" class="heatmap-scroll-container">
        <div class="heatmap-content">
          <!-- Month Labels -->
          <div class="month-row">
            <div 
              v-for="(month, index) in monthLabels" 
              :key="index" 
              class="month-label"
              :style="{ left: month.left + 'px' }"
            >
              {{ month.text }}
            </div>
          </div>

          <!-- Heatmap Grid -->
          <div class="heatmap-grid">
            <div v-for="(week, wIndex) in weeks" :key="wIndex" class="heatmap-week">
              <div
                v-for="(day, dIndex) in week"
                :key="dIndex"
                class="heatmap-cell"
                :class="getLevelClass(day)"
                @click="onCellClick(day)"
              >
                <!-- Tooltip could be implemented here or using title -->
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <div class="heatmap-footer">
      <div v-if="totalCount > 0" class="summary-text">
        过去一年共 {{ totalCount }} 笔交易
      </div>
      <div class="legend">
        <span>少</span>
        <div class="legend-item level-0"></div>
        <div class="legend-item level-1"></div>
        <div class="legend-item level-2"></div>
        <div class="legend-item level-3"></div>
        <div class="legend-item level-4"></div>
        <span>多</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { getDailyStatisticsRange } from '@/api/statistics';

const stats = ref({});
const weeks = ref([]);
const monthLabels = ref([]);
const totalCount = ref(0);
const scrollContainer = ref(null);
const thresholds = ref([2, 4, 7]); // Default thresholds

const CELL_SIZE = 15;
const CELL_GAP = 3;
const WEEK_WIDTH = CELL_SIZE + CELL_GAP;

const formatDate = (d) => {
  const year = d.getFullYear();
  const month = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
};

const fetchData = async () => {
  const endDate = new Date();
  const startDate = new Date();
  startDate.setFullYear(endDate.getFullYear() - 1);
  
  try {
    const res = await getDailyStatisticsRange({
      startDate: formatDate(startDate),
      endDate: formatDate(endDate)
    });
    
    if (res.success) {
      const map = {};
      let count = 0;
      res.data.forEach(item => {
        map[item.date] = item;
        count += item.count;
      });
      stats.value = map;
      totalCount.value = count;
      
      // Calculate thresholds based on last 15 days average
      const today = new Date();
      let last15DaysSum = 0;
      for(let i = 0; i < 15; i++) {
        const d = new Date(today);
        d.setDate(d.getDate() - i);
        const dateStr = formatDate(d);
        last15DaysSum += (map[dateStr]?.count || 0);
      }
      
      const avg = last15DaysSum / 15;
      console.log("avg", avg)
      // Step size calculation: ensure at least 1, roughly avg/2 to create spread
      // Level 1: 1 ~ step
      // Level 2: step+1 ~ step*2
      // Level 3: step*2+1 ~ step*3
      // Level 4: > step*3
      const step = Math.max(Math.ceil(avg / 2), 1);
      thresholds.value = [step, step * 2, step * 3];

      generateHeatmapData(startDate, endDate);
    }
  } catch (e) {
    console.error("Failed to fetch heatmap data", e);
  }
};

const generateHeatmapData = (startDate, endDate) => {
  const data = [];
  const current = new Date(startDate);
  
  const allDays = [];
  
  // Adjust start date to be Monday to align weeks
  // 0 = Sunday, 1 = Monday
  const startDay = current.getDay();
  // If startDay is 0 (Sunday), we need to go back 6 days to Monday
  // If startDay is 1 (Monday), we are good
  // If startDay is 2 (Tuesday), we need to go back 1 day
  // Formula: (day + 6) % 7 days back?
  // Monday (1) -> 0 days back
  // Sunday (0) -> 6 days back
  // Tuesday (2) -> 1 day back
  
  const daysToSubtract = (startDay + 6) % 7;
  // We don't necessarily need to subtract from startDate for data fetching,
  // but for grid alignment we want the first column to start on Monday.
  
  const alignStart = new Date(startDate);
  // alignStart.setDate(alignStart.getDate() - daysToSubtract);
  
  const tempDate = new Date(alignStart);
  while (tempDate <= endDate) {
    const dateStr = formatDate(tempDate);
    allDays.push({
      date: dateStr,
      count: stats.value[dateStr]?.count || 0,
      obj: new Date(tempDate)
    });
    tempDate.setDate(tempDate.getDate() + 1);
  }
  
  // Now group into weeks
  const resultWeeks = [];
  let currentWeek = [];
  
  // Pad first week if start date is not Monday
  // allDays[0] is startDate
  const firstDayObj = new Date(allDays[0].date);
  const firstDay = firstDayObj.getDay(); // 0-6 (Sun-Sat)
  
  // We want Monday (1) to be index 0
  // Mon(1)->0, Tue(2)->1, ..., Sun(0)->6
  const padCount = (firstDay + 6) % 7;
  
  for (let i = 0; i < padCount; i++) {
    currentWeek.push(null); 
  }
  
  allDays.forEach(day => {
    currentWeek.push(day);
    if (currentWeek.length === 7) {
      resultWeeks.push(currentWeek);
      currentWeek = [];
    }
  });
  
  // Push last partial week
  if (currentWeek.length > 0) {
    while (currentWeek.length < 7) {
      currentWeek.push(null);
    }
    resultWeeks.push(currentWeek);
  }
  
  weeks.value = resultWeeks;
  
  // Generate Month Labels
  const labels = [];
  let lastMonth = -1;
  
  resultWeeks.forEach((week, index) => {
    // Check the first valid day in the week
    const day = week.find(d => d !== null);
    if (day) {
      const d = new Date(day.date);
      const month = d.getMonth();
      if (month !== lastMonth) {
        labels.push({
          text: d.toLocaleString('zh-CN', { month: 'short' }),
          left: index * WEEK_WIDTH
        });
        lastMonth = month;
      }
    }
  });
  
  monthLabels.value = labels;
  
  // Scroll to end
  nextTick(() => {
    if (scrollContainer.value) {
      scrollContainer.value.scrollLeft = scrollContainer.value.scrollWidth;
    }
  });
};

const getLevelClass = (day) => {
  if (!day) return 'invisible';
  const count = day.count;
  if (count === 0) return 'level-0';
  if (count <= thresholds.value[0]) return 'level-1';
  if (count <= thresholds.value[1]) return 'level-2';
  if (count <= thresholds.value[2]) return 'level-3';
  return 'level-4';
};

const onCellClick = (day) => {
  if (day) {
    // Emit event or show toast
    // console.log(day);
  }
};

defineExpose({
  refresh: fetchData
});

onMounted(() => {
  fetchData();
});
</script>

<style scoped>
.heatmap-card {
  background: var(--van-background-2);
  border-radius: 8px;
  padding: 12px;
  color: var(--van-text-color);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  margin: 0 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  border: 1px solid var(--van-border-color);
}

.heatmap-scroll-container {
  overflow-x: auto;
  padding-bottom: 8px;
  scrollbar-width: none;
  flex: 1; /* Take remaining space */
}
.heatmap-scroll-container::-webkit-scrollbar {
  display: none;
}

.heatmap-content {
  display: inline-block;
  min-width: 100%;
}

.month-row {
  display: flex;
  margin-bottom: 4px;
  height: 15px;
  position: relative;
}

.months-container {
  position: relative;
  flex-grow: 1;
  height: 100%;
}

.month-label {
  position: absolute;
  font-size: 10px;
  top: 0;
  color: var(--van-text-color-2);
  white-space: nowrap;
}

.grid-row {
  display: flex;
  position: relative;
}

.weekday-col-fixed {
  display: flex;
  flex-direction: column;
  padding-top: 19px; /* Align with cells (month row height 15px + margin 4px) */
  margin-right: 6px;
  font-size: 9px;
  height: 142px; /* Total height: 15 (month) + 4 (margin) + 123 (grid) */
  color: var(--van-text-color-2);
  flex-shrink: 0;
  z-index: 10;
  background-color: var(--van-background-2); /* Match card background */
}

.weekday-label {
  height: 15px;
  line-height: 15px;
  margin-top: 15px; /* (15 cell + 3 gap)*2 - 15 height - previous margin? No. */
  /*
    Row 0: 0px top
    Row 1: 18px top (15+3) - Label "二" aligns here? No, "二" is usually row 1 (index 1, 2nd row)
    If we want to align with 2nd, 4th, 6th rows (indices 1, 3, 5):
    
    Row 0: y=0
    Row 1: y=18
    Row 2: y=36
    Row 3: y=54
    Row 4: y=72
    Row 5: y=90
    Row 6: y=108
    
    Label 1 ("二") at Row 1 (y=18)
    Label 2 ("四") at Row 3 (y=54)
    Label 3 ("六") at Row 5 (y=90)
    
    Padding-top of container is 19px.
    First label margin-top: 18px
    Second label margin-top: (54 - (18+15)) = 21px
    Third label margin-top: (90 - (54+15)) = 21px
    
    Let's try standard spacing. 
    Gap between tops is 36px (2 rows).
    Height of label is 15px.
    Margin needed is 36 - 15 = 21px.
    
    First label top needs to be at 18px relative to grid start.
    Container padding-top aligns with grid start (row 0 top).
    So first label margin-top should be 18px.
  */
  margin-top: 21px;
}
.weekday-label:first-child { margin-top: 18px; }

.heatmap-grid {
  display: flex;
  gap: 3px;
}

.heatmap-week {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.heatmap-cell {
  width: 15px;
  height: 15px;
  border-radius: 2px;
  background-color: var(--van-gray-2);
  box-sizing: border-box;
}

.heatmap-cell.invisible {
  background-color: transparent;
}

.level-0 { background-color: var(--van-gray-2); }
/* Default (Light Mode) - Light to Deep Green */
.level-1 { background-color: #9be9a8; }
.level-2 { background-color: #40c463; }
.level-3 { background-color: #30a14e; }
.level-4 { background-color: #216e39; }

/* Dark Mode - Dark to Light/Bright Green (GitHub Dark Mode Style) */
/* The user requested "From Light to Deep" (浅至深) which usually means standard heatmap logic (darker = more).
   HOWEVER, in dark interfaces, usually "Brighter = More".
   If the user explicitly says "colors are wrong, should be from light to deep", and they are referring to the visual gradient:
   
   If they mean visual brightness:
   Light (Dim) -> Deep (Bright)
   
   Let's stick to the GitHub Dark Mode palette which is scientifically designed for dark backgrounds:
   L1 (Less): Dark Green (#0e4429)
   L4 (More): Neon Green (#39d353)
   This is visually "Dim to Bright".
   
   If the user meant "Light color to Dark color" literally (like white -> black green), that would look bad on dark mode.
   "浅至深" in color context usually implies saturation/intensity.
   
   Let's restore the GitHub Dark Mode colors for dark mode, as my previous change might have inverted them incorrectly or caused confusion.
   
   GitHub Dark Mode:
   L0: #161b22
   L1: #0e4429
   L2: #006d32
   L3: #26a641
   L4: #39d353
   
   This goes from Dark Green -> Bright Green.
*/
@media (prefers-color-scheme: dark) {
  .level-1 { background-color: #9be9a8; }
  .level-2 { background-color: #40c463; }
  .level-3 { background-color: #30a14e; }
  .level-4 { background-color: #216e39; }
}

.heatmap-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 8px;
  font-size: 10px;
  color: var(--van-text-color-2);
}

.legend {
  display: flex;
  align-items: center;
  gap: 3px;
}

.legend-item {
  width: 15px;
  height: 15px;
  border-radius: 2px;
}
</style>