<!-- eslint-disable vue/no-v-html -->
<template>
  <van-config-provider
    :theme="theme"
    class="config-provider-full-height"
  >
    <div class="page-container-flex budget-v2-wrapper">
      <!-- 页头：DateSelectHeader -->
      <DateSelectHeader
        type="month"
        :current-date="currentDate"
        @prev="handlePrevMonth"
        @next="handleNextMonth"
        @jump="showDatePicker = true"
      >
        <template #right>
          <!-- 未覆盖分类警告图标（支出和收入 tab） -->
          <van-icon
            v-if="
              activeTab !== BudgetCategory.Savings && uncoveredCategories.length > 0 && !isArchive
            "
            name="warning-o"
            size="20"
            color="var(--van-danger-color)"
            style="margin-right: 12px"
            title="查看未覆盖预算的分类"
            @click="showUncoveredDetails = true"
          />
          <!-- 归档图标（历史月份） -->
          <van-icon
            v-if="isArchive"
            name="comment-o"
            size="20"
            title="已归档月份总结"
            style="margin-right: 12px"
            @click="showArchiveSummary()"
          />
          <!-- 储蓄配置图标（存款计划 tab） -->
          <van-icon
            v-if="activeTab === BudgetCategory.Savings"
            name="setting-o"
            size="20"
            title="储蓄分类配置"
            @click="savingsConfigRef.open()"
          />
        </template>
      </DateSelectHeader>

      <!-- 业务类型选择器 -->
      <div>
        <BudgetTypeTabs
          :active-tab="activeTab"
          @change="handleTabChange"
        />
      </div>

      <!-- 可滚动内容区域 -->
      <div class="budget-scroll-content">
        <!-- 下拉刷新 -->
        <van-pull-refresh
          v-model="refreshing"
          @refresh="onRefresh"
        >
          <!-- 加载状态 -->
          <van-loading
            v-if="loading"
            vertical
            style="padding: 100px 0"
          >
            加载预算数据中...
          </van-loading>

          <!-- 错误状态 -->
          <div
            v-else-if="hasError"
            class="error-state"
          >
            <van-empty
              image="error"
              :description="errorMessage || '加载数据时出现错误'"
            >
              <van-button
                type="primary"
                size="small"
                @click="retryLoad"
              >
                重试
              </van-button>
            </van-empty>
          </div>

          <!-- 预算内容 -->
          <div
            v-else
            class="budget-content"
            @touchstart="handleTouchStart"
            @touchmove="handleTouchMove"
            @touchend="handleTouchEnd"
          >
            <!-- 支出内容 -->
            <ExpenseBudgetContent
              v-if="activeTab === BudgetCategory.Expense"
              :budgets="expenseBudgets"
              :stats="overallStats"
              :uncovered-categories="uncoveredCategories"
              :selected-date="selectedDate"
              @delete="handleDelete"
              @edit="handleEdit"
            />

            <!-- 收入内容 -->
            <IncomeBudgetContent
              v-else-if="activeTab === BudgetCategory.Income"
              :budgets="incomeBudgets"
              :stats="overallStats"
              :uncovered-categories="uncoveredCategories"
              :selected-date="selectedDate"
              @delete="handleDelete"
              @edit="handleEdit"
            />

            <!-- 计划内容 -->
            <SavingsBudgetContent
              v-else-if="activeTab === BudgetCategory.Savings"
              :budgets="savingsBudgets"
              @savings-nav="handleSavingsNav"
            />
          </div>

          <!-- 底部安全距离 -->
          <div style="height: calc(95px + env(safe-area-inset-bottom, 0px))" />
        </van-pull-refresh>
      </div>

      <!-- 悬浮编辑按钮（支出和收入 tab） -->
      <van-floating-bubble
        v-if="activeTab !== BudgetCategory.Savings"
        v-model:offset="bubbleOffset"
        icon="edit"
        axis="xy"
        magnetic="x"
        @click="showListPopup = true"
      />

      <!-- 预算编辑弹窗 -->
      <BudgetEditPopup
        ref="budgetEditRef"
        @success="loadBudgetData"
      />

      <!-- 储蓄配置弹窗 -->
      <SavingsConfigPopup
        ref="savingsConfigRef"
        @change="loadBudgetData"
      />

      <!-- 未覆盖分类弹窗 -->
      <PopupContainerV2
        v-model:show="showUncoveredDetails"
        title="未覆盖预算的分类"
        :height="'60%'"
      >
        <div style="padding: 0">
          <!-- subtitle 作为内容区域顶部 -->
          <div
            style="padding: 12px 16px; text-align: center; color: #999; font-size: 14px; border-bottom: 1px solid var(--van-border-color)"
            v-html="`本月共 <b style='color:var(--van-primary-color)'>${uncoveredCategories.length}</b> 个分类未设置预算`"
          />

          <div class="uncovered-list">
            <div
              v-for="item in uncoveredCategories"
              :key="item.category"
              class="uncovered-item"
            >
              <div class="item-left">
                <div class="category-name">
                  {{ item.category }}
                </div>
                <div class="transaction-count">
                  {{ item.transactionCount }} 笔记录
                </div>
              </div>
              <div class="item-right">
                <div
                  class="item-amount"
                  :class="activeTab === BudgetCategory.Expense ? 'expense' : 'income'"
                >
                  ¥{{ formatMoney(item.totalAmount) }}
                </div>
              </div>
            </div>
          </div>
        </div>

        <template #footer>
          <van-button
            block
            round
            type="primary"
            @click="showUncoveredDetails = false"
          >
            我知道了
          </van-button>
        </template>
      </PopupContainerV2>

      <!-- 归档总结弹窗 -->
      <PopupContainerV2
        v-model:show="showSummaryPopup"
        title="月份归档总结"
        :height="'70%'"
      >
        <div style="padding: 0">
          <!-- subtitle -->
          <div style="padding: 12px 16px; text-align: center; color: #999; font-size: 14px; border-bottom: 1px solid var(--van-border-color)">
            {{ selectedDate.getFullYear() }}年{{ selectedDate.getMonth() + 1 }}月
          </div>

          <div style="padding: 16px">
            <div
              class="rich-html-content"
              v-html="
                archiveSummary ||
                  '<p style=\'text-align:center;color:var(--van-text-color-3)\'>暂无总结</p>'
              "
            />
          </div>
        </div>
      </PopupContainerV2>

      <!-- 日期选择器 -->
      <van-popup
        v-model:show="showDatePicker"
        position="bottom"
        round
      >
        <van-date-picker
          v-model="pickerDate"
          title="选择年月"
          :min-date="minDate"
          :max-date="maxDate"
          :columns-type="['year', 'month']"
          @confirm="onDatePickerConfirm"
          @cancel="showDatePicker = false"
        />
      </van-popup>
    </div>
  </van-config-provider>
</template>

<script setup>
import { ref, computed, onMounted, watch, onBeforeUnmount, onActivated } from 'vue'
import { showToast, showConfirmDialog } from 'vant'
import dayjs from 'dayjs'
import {
  getBudgetList,
  deleteBudget,
  getCategoryStats,
  getUncoveredCategories,
  getArchiveSummary,
  getSavingsBudget
} from '@/api/budget'
import { BudgetPeriodType, BudgetCategory } from '@/constants/enums'
import DateSelectHeader from '@/components/DateSelectHeader.vue'
import BudgetTypeTabs from '@/components/BudgetTypeTabs.vue'
import BudgetCard from '@/components/Budget/BudgetCard.vue'
import BudgetEditPopup from '@/components/Budget/BudgetEditPopup.vue'
import SavingsConfigPopup from '@/components/Budget/SavingsConfigPopup.vue'
import PopupContainerV2 from '@/components/PopupContainerV2.vue'
import ExpenseBudgetContent from './modules/ExpenseBudgetContent.vue'
import IncomeBudgetContent from './modules/IncomeBudgetContent.vue'
import SavingsBudgetContent from './modules/SavingsBudgetContent.vue'
import { useMessageStore } from '@/stores/message'

// 为组件缓存设置名称
defineOptions({
  name: 'BudgetV2View'
})

const messageStore = useMessageStore()
const theme = computed(() => (messageStore.isDarkMode ? 'dark' : 'light'))

// 日期状态
const currentDate = ref(new Date())
const selectedDate = ref(new Date())
const showDatePicker = ref(false)
const minDate = new Date(2020, 0, 1)
const maxDate = new Date()
const pickerDate = ref([
  selectedDate.value.getFullYear().toString(),
  (selectedDate.value.getMonth() + 1).toString().padStart(2, '0')
])

// 业务 tab 状态
const activeTab = ref(BudgetCategory.Expense)

// 数据状态
const expenseBudgets = ref([])
const incomeBudgets = ref([])
const savingsBudgets = ref([])
const overallStats = ref({
  month: { rate: '0.0', current: 0, limit: 0, count: 0 },
  year: { rate: '0.0', current: 0, limit: 0, count: 0 }
})

// UI 状态
const loading = ref(false)
const refreshing = ref(false)
const hasError = ref(false)
const errorMessage = ref('')

// 未覆盖分类状态
const uncoveredCategories = ref([])
const showUncoveredDetails = ref(false)

// 归档总结状态
const showSummaryPopup = ref(false)
const archiveSummary = ref('')

// 弹窗状态
const showListPopup = ref(false)
const budgetEditRef = ref(null)
const savingsConfigRef = ref(null)

// 悬浮按钮位置
const bubbleOffset = ref({
  x: window.innerWidth - 48 - 24,
  y: window.innerHeight - 48 - 100
})

// 触摸手势状态（用于左右滑动切换月份）
const touchStartX = ref(0)
const touchStartY = ref(0)
const touchEndX = ref(0)
const touchEndY = ref(0)

// 计算属性
const isArchive = computed(() => {
  const now = new Date()
  return (
    selectedDate.value.getFullYear() < now.getFullYear() ||
    (selectedDate.value.getFullYear() === now.getFullYear() &&
      selectedDate.value.getMonth() < now.getMonth())
  )
})

const popupTitle = computed(() => {
  switch (activeTab.value) {
    case BudgetCategory.Expense:
      return '支出预算明细'
    case BudgetCategory.Income:
      return '收入预算明细'
    default:
      return '预算明细'
  }
})

// 监听 activeTab 变化，触发数据刷新
watch(activeTab, async () => {
  await Promise.allSettled([loadCategoryStats(), loadUncoveredCategories()])
})

// Tab 切换处理
const handleTabChange = (tab) => {
  activeTab.value = tab
}

// 监听 selectedDate 变化，触发数据刷新
watch(selectedDate, async () => {
  await loadBudgetData()
})

// 月份切换逻辑
const handlePrevMonth = async () => {
  const newDate = new Date(currentDate.value)
  newDate.setMonth(newDate.getMonth() - 1)
  currentDate.value = newDate
  selectedDate.value = newDate
}

const handleNextMonth = async () => {
  if (isCurrentMonth()) {
    return // 禁止切换到未来月份
  }
  const newDate = new Date(currentDate.value)
  newDate.setMonth(newDate.getMonth() + 1)
  currentDate.value = newDate
  selectedDate.value = newDate
}

const isCurrentMonth = () => {
  const now = new Date()
  return (
    currentDate.value.getFullYear() === now.getFullYear() &&
    currentDate.value.getMonth() === now.getMonth()
  )
}

// 左右滑动手势切换月份
const handleSwipeMonth = (offset) => {
  if (offset > 0) {
    handleNextMonth()
  } else {
    handlePrevMonth()
  }
}

// 触摸事件处理（左右滑动切换月份）
const handleTouchStart = (e) => {
  touchStartX.value = e.touches[0].clientX
  touchStartY.value = e.touches[0].clientY
  touchEndX.value = touchStartX.value
  touchEndY.value = touchStartY.value
}

const handleTouchMove = (e) => {
  touchEndX.value = e.touches[0].clientX
  touchEndY.value = e.touches[0].clientY
}

const handleTouchEnd = () => {
  const deltaX = touchEndX.value - touchStartX.value
  const deltaY = touchEndY.value - touchStartY.value
  const minSwipeDistance = 50

  // 判断是否是水平滑动（水平距离大于垂直距离且超过阈值）
  if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > minSwipeDistance) {
    if (deltaX > 0) {
      // 右滑 - 上一个月
      handlePrevMonth()
    } else {
      // 左滑 - 下一个月
      handleNextMonth()
    }
  }

  // 重置触摸位置
  touchStartX.value = 0
  touchStartY.value = 0
  touchEndX.value = 0
  touchEndY.value = 0
}

// 下拉刷新
const onRefresh = async () => {
  hasError.value = false
  errorMessage.value = ''
  await loadBudgetData()
  refreshing.value = false
  showToast('刷新成功')
}

// 日期选择器
const onDatePickerConfirm = ({ selectedValues }) => {
  const [year, month] = selectedValues
  const newDate = new Date(parseInt(year), parseInt(month) - 1, 1)

  // 检查是否超过当前月
  const today = new Date()
  if (
    newDate.getFullYear() > today.getFullYear() ||
    (newDate.getFullYear() === today.getFullYear() && newDate.getMonth() > today.getMonth())
  ) {
    showToast('不能选择未来的月份')
    showDatePicker.value = false
    return
  }

  currentDate.value = newDate
  selectedDate.value = newDate
  showDatePicker.value = false
}

// 数据加载核心逻辑
const loadBudgetData = async () => {
  if (loading.value && !refreshing.value) {
    return // 防止重复加载
  }

  loading.value = !refreshing.value
  hasError.value = false
  errorMessage.value = ''

  try {
    // 并发加载多个数据源
    await Promise.allSettled([loadMonthlyData(), loadCategoryStats(), loadUncoveredCategories()])
  } catch (_error) {
    console.error('加载预算数据失败:', _error)
    hasError.value = true
    errorMessage.value = _error.message || '网络连接异常，请检查网络后重试'
  } finally {
    loading.value = false
  }
}

// 加载月度数据
const loadMonthlyData = async () => {
  try {
    const res = await getBudgetList(dayjs(selectedDate.value).format('YYYY-MM-DD'))
    if (res.success) {
      const data = res.data || []
      expenseBudgets.value = data.filter((b) => b.category === BudgetCategory.Expense)
      incomeBudgets.value = data.filter((b) => b.category === BudgetCategory.Income)
      savingsBudgets.value = data.filter((b) => b.category === BudgetCategory.Savings)
    }
  } catch (err) {
    console.error('加载预算列表失败', err)
  }
}

// 加载分类统计
const loadCategoryStats = async () => {
  try {
    const res = await getCategoryStats(
      activeTab.value,
      dayjs(selectedDate.value).format('YYYY-MM-DD')
    )
    if (res.success) {
      const data = res.data
      overallStats.value = {
        month: {
          rate: data.month?.usagePercentage?.toFixed(1) || '0.0',
          current: data.month?.current || 0,
          limit: data.month?.limit || 0,
          count: data.month?.count || 0,
          trend: data.month?.trend || [],
          description: data.month?.description || ''
        },
        year: {
          rate: data.year?.usagePercentage?.toFixed(1) || '0.0',
          current: data.year?.current || 0,
          limit: data.year?.limit || 0,
          count: data.year?.count || 0,
          trend: data.year?.trend || [],
          description: data.year?.description || ''
        }
      }
    }
  } catch (err) {
    console.error('加载分类统计失败', err)
  }
}

// 加载未覆盖分类
const loadUncoveredCategories = async () => {
  if (activeTab.value === BudgetCategory.Savings) {
    uncoveredCategories.value = []
    return
  }
  try {
    const res = await getUncoveredCategories(
      activeTab.value,
      dayjs(selectedDate.value).format('YYYY-MM-DD')
    )
    if (res.success) {
      uncoveredCategories.value = res.data || []
    }
  } catch (err) {
    console.error('获取未覆盖分类失败', err)
  }
}

// 加载归档总结
const showArchiveSummary = async () => {
  try {
    const res = await getArchiveSummary(dayjs(selectedDate.value).format('YYYY-MM-DD'))
    if (res.success) {
      archiveSummary.value = res.data || ''
      showSummaryPopup.value = true
    }
  } catch (err) {
    console.error('获取总结失败', err)
    showToast('获取总结失败')
  }
}

// 重试加载
const retryLoad = () => {
  hasError.value = false
  errorMessage.value = ''
  loadBudgetData()
}

// 预算操作
const handleEdit = (budget) => {
  budgetEditRef.value.open({
    data: budget,
    isEditFlag: true,
    category: budget.category
  })
}

const handleDelete = async (budget) => {
  try {
    await showConfirmDialog({
      title: '删除预算',
      message: `确定要删除预算 "${budget.name}" 吗？`
    })

    const res = await deleteBudget(budget.id)
    if (res.success) {
      showToast('删除成功')
      await loadBudgetData()
    } else {
      showToast(res.message || '删除失败')
    }
  } catch (err) {
    if (err.message !== 'cancel') {
      console.error('删除预算失败', err)
      showToast('删除预算失败')
    }
  }
}

// 存款计划日期切换
const handleSavingsNav = async (budget, offset) => {
  if (!budget.periodStart) {
    return
  }

  const date = new Date(budget.periodStart)
  let year = date.getFullYear()
  let month = date.getMonth() + 1

  if (budget.type === BudgetPeriodType.Year) {
    year += offset
  } else {
    month += offset
    if (month > 12) {
      month = 1
      year++
    } else if (month < 1) {
      month = 12
      year--
    }
  }

  try {
    const res = await getSavingsBudget(year, month, budget.type)
    if (res.success && res.data) {
      const index = savingsBudgets.value.findIndex((b) => b.id === budget.id)
      if (index !== -1) {
        savingsBudgets.value[index] = res.data
      }
    } else {
      showToast('获取数据失败')
    }
  } catch (err) {
    console.error('切换日期失败', err)
    showToast('切换日期失败')
  }
}

// 辅助函数
const formatMoney = (val) => {
  return parseFloat(val || 0).toLocaleString(undefined, {
    minimumFractionDigits: 0,
    maximumFractionDigits: 0
  })
}

const getPeriodLabel = (type) => {
  const isCurrent = (date) => {
    const now = new Date()
    return date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth()
  }
  const isCurrentYear = (date) => {
    const now = new Date()
    return date.getFullYear() === now.getFullYear()
  }

  if (type === BudgetPeriodType.Month) {
    return isCurrent(selectedDate.value) ? '本月' : `${selectedDate.value.getMonth() + 1}月`
  }
  if (type === BudgetPeriodType.Year) {
    return isCurrentYear(selectedDate.value) ? '本年' : `${selectedDate.value.getFullYear()}年`
  }
  return '周期'
}

const getProgressColor = (budget) => {
  if (!budget.limit || budget.limit === 0) {
    return 'var(--van-primary-color)'
  }

  const ratio = Math.min(Math.max(budget.current / budget.limit, 0), 1)

  const interpolate = (start, end, t) => {
    return Math.round(start + (end - start) * t)
  }

  const getGradientColor = (value, stops) => {
    let startStop = stops[0]
    let endStop = stops[stops.length - 1]

    for (let i = 0; i < stops.length - 1; i++) {
      if (value >= stops[i].p && value <= stops[i + 1].p) {
        startStop = stops[i]
        endStop = stops[i + 1]
        break
      }
    }

    const range = endStop.p - startStop.p
    const t = (value - startStop.p) / range

    const r = interpolate(startStop.c.r, endStop.c.r, t)
    const g = interpolate(startStop.c.g, endStop.c.g, t)
    const b = interpolate(startStop.c.b, endStop.c.b, t)

    return `rgb(${r}, ${g}, ${b})`
  }

  let stops

  if (budget.category === BudgetCategory.Expense) {
    stops = [
      { p: 0, c: { r: 64, g: 169, b: 255 } },
      { p: 0.4, c: { r: 54, g: 207, b: 201 } },
      { p: 0.7, c: { r: 250, g: 173, b: 20 } },
      { p: 1, c: { r: 255, g: 77, b: 79 } }
    ]
  } else {
    stops = [
      { p: 0, c: { r: 245, g: 34, b: 45 } },
      { p: 0.45, c: { r: 255, g: 204, b: 204 } },
      { p: 0.5, c: { r: 240, g: 242, b: 245 } },
      { p: 0.55, c: { r: 186, g: 231, b: 255 } },
      { p: 1, c: { r: 24, g: 144, b: 255 } }
    ]
  }

  return getGradientColor(ratio, stops)
}

// 全局事件监听
const handleTransactionsChanged = () => {
  const temp = selectedDate.value
  selectedDate.value = new Date(temp)
}

// 生命周期
onMounted(async () => {
  try {
    await loadBudgetData()
    window.addEventListener('transactions-changed', handleTransactionsChanged)
  } catch (err) {
    console.error('获取初始化数据失败', err)
  }
})

onActivated(() => {
  // 从缓存恢复时刷新数据
})

onBeforeUnmount(() => {
  window.removeEventListener('transactions-changed', handleTransactionsChanged)
})
</script>

<style scoped lang="scss">
.config-provider-full-height {
  height: 100%;
}

.budget-v2-wrapper {
  font-family: var(--font-primary);
  color: var(--text-primary);
}

.budget-scroll-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  background-color: var(--bg-primary);
  /* 改善滚动性能 */
  will-change: scroll-position;
  /* 防止滚动卡顿 */
  scroll-behavior: smooth;
}

.budget-content {
  padding: var(--spacing-md);
  padding-top: 0;
}

.error-state {
  padding: 100px 16px;
  text-align: center;
}

.budget-list {
  padding-top: 8px;
  padding-bottom: 20px;
}

.budget-list :deep(.van-swipe-cell) {
  margin: 0 12px 12px;
}

.delete-button {
  height: 100%;
}

.uncovered-list {
  padding: 12px 16px;
}

.uncovered-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  background-color: var(--van-background-2);
  border-radius: 12px;
  margin-bottom: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.item-left {
  display: flex;
  flex-direction: column;
}

.category-name {
  font-size: 16px;
  font-weight: 500;
  color: var(--van-text-color);
  margin-bottom: 4px;
}

.transaction-count {
  font-size: 12px;
  color: var(--van-text-color-2);
}

.item-right {
  text-align: right;
}

.item-amount {
  font-size: 18px;
  font-weight: 600;
  font-family:
    DIN Alternate,
    system-ui;
}

.info-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.info-item .label {
  font-size: 12px;
  color: var(--van-text-color-2);
  margin-bottom: 4px;
}

.info-item .value {
  font-size: 16px;
  font-weight: 600;
  font-family:
    DIN Alternate,
    system-ui;
}

.info-item .value.expense {
  color: var(--van-danger-color);
}

.info-item .value.income {
  color: var(--van-success-color);
}

:deep(.van-nav-bar) {
  background: transparent !important;
}
</style>
