<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
// 引入您的真实接口函数
import { TradingPair } from '@/api/index.js';
import { useRoute, useRouter } from "vue-router";

const router = useRouter();

// --- 1. 状态管理 ---
const tabs = [
  { key: 'fav', label: '自选' },
  { key: 'spot', label: '币币' },
  { key: 'futures', label: '合约' },
  { key: 'seconds', label: '秒合约' }
];

const currentTab = ref('spot');
const listData = ref([]);
const page = ref(1);
const loading = ref(false);
const finished = ref(false);
const scrollContainer = ref(null);
const PAGE_SIZE = 15; // 定义分页大小

// --- 2. WebSocket 核心变量 ---
const socket = ref(null);
let reconnectTimer = null; // 重连定时器
let heartbeatTimer = null; // 心跳定时器
let isManualClose = false; // 标记是否为手动关闭（切换Tab时），避免触发重连
let lastSymbols = [];      // 记录最后一次订阅的币种，用于重连

// --- 3. 图表与图标工具函数 ---
const generateChartPaths = (isUp) => {
  const width = 60; const height = 24; const pointCount = 15; const step = width / (pointCount - 1);
  let points = []; let y = isUp ? (height * 0.8) : (height * 0.2);
  for(let i=0; i<pointCount; i++) {
    const x = i * step;
    y += (Math.random() - 0.5) * (height * 0.4) + (isUp ? -(height * 0.05) : (height * 0.05));
    y = Math.max(2, Math.min(height - 2, y));
    points.push({x, y});
  }
  const linePath = `M ${points.map(p => `${p.x},${p.y}`).join(' L ')}`;
  const fillPath = `${linePath} L ${width},${height + 5} L 0,${height + 5} Z`;
  return { linePath, fillPath };
};

// 本地 SVG 图标映射 (作为兜底备用)
const localIcons = {
  BTC: '<path fill="#F7931A" d="M22.6 13.4c.4-2.6-1.6-4-4.3-4.9l.9-3.5-2.1-.5-.9 3.5c-.5-.1-1.1-.3-1.7-.4l.9-3.5-2.1-.5-.9 3.5c-.4-.1-1-.2-1.5-.3l-3-.7-.6 2.4s1.6.4 1.6.4c.9.2 1 .8 1 1.2l-1 4c.1 0 .1 0 .1.1l-1.4 5.6c0 .3-.3.8-1 .6 0 0-1.6-.4-1.6-.4l-1.1 2.6 2.8.7c.5.1 1 .3 1.5.4l-.9 3.6 2.1.5.9-3.6c.6.2 1.1.3 1.7.5l-.9 3.6 2.1.5.9-3.5c3.7.7 6.4.4 7.6-2.9.9-2.6-.1-4.1-1.9-5.1 1.4-.3 2.4-1.2 2.7-3z"/>',
  ETH: '<path fill="#627EEA" d="M11.9 20.3L6.1 16.9l5.8-2.6 5.8 2.6-5.8 3.4zm0-9.6l5.8 2.6-5.8 8.1-5.8-8.1 5.8-2.6zM12 2l5.8 9.6L12 14 6.2 11.6 12 2z"/>',
  BNB: '<path fill="#F3BA2F" d="M4.6 12l2.3-2.3L9.2 12l-2.3 2.3L4.6 12zM12 4.6l2.3 2.3-2.3 2.3-2.3-2.3L12 4.6zm7.4 7.4l-2.3 2.3 2.3 2.3 2.3-2.3-2.3-2.3zm-7.4 7.4l-2.3-2.3 2.3-2.3 2.3 2.3-2.3 2.3zm4.6-7.4l2.3-2.3-2.3-2.3-2.3 2.3 2.3 2.3zM12 14.8l-2.3-2.3 2.3-2.3 2.3 2.3L12 14.8zM9.7 7.4L12 5.1l2.3 2.3L12 9.7 9.7 7.4z"/>',
  USDT: '<path fill="#26A17B" d="M14.5 10.4c.2-.2.3-.3.3-.3s-.1 0-.3 0c-.5.1-1.2.1-1.9.1-.1-2.9 0-2.9 0-2.9h3.1V5.7h-3.1V3H11v2.7H8V7.3h3v2.9c0 .1 0 .2-.1.2-2.8 0-5.1.8-5.1 1.7 0 1 2.3 1.7 5.2 1.7s5.2-.8 5.2-1.7c0-.7-1.3-1.2-3.4-1.5z"/>',
  XRP: '<path fill="#23292F" d="M12 24c6.627 0 12-5.373 12-12S18.627 0 12 0 0 5.373 0 12s5.373 12 12 12z" /><path fill="#FFF" d="M9.82 12.01L4.65 6.84a.856.856 0 011.21-1.21l5.17 5.17a1.14 1.14 0 010 1.62L5.86 17.59a.856.856 0 01-1.21-1.21l5.17-4.37zM14.18 12.01l5.17 5.17a.856.856 0 01-1.21 1.21l-5.17-5.17a1.14 1.14 0 010-1.62l5.17-5.17a.856.856 0 011.21 1.21l-5.17 4.37z"/>',
  SOL: '<path fill="#00FFA3" d="M3.5 16.5l2.1-3.6 14.9 0L18.4 16.5 3.5 16.5zM5.6 7.5L3.5 11.1 18.4 11.1 20.5 7.5 5.6 7.5zM20.5 20.1l-2.1 3.6L3.5 23.7 5.6 20.1 20.5 20.1z"/>',
  DOGE: '<path fill="#C2A633" d="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,18c-3.31,0-6-2.69-6-6s2.69-6,6-6s6,2.69,6,6S15.31,18,12,18z"/>'
};

// --- 4. 生产级 WebSocket 管理 ---

// 启动心跳：防止连接因长时间无数据而被断开
const startHeartbeat = () => {
  clearInterval(heartbeatTimer);
  heartbeatTimer = setInterval(() => {
    if (socket.value && socket.value.readyState === WebSocket.OPEN) {
      // 发送 ping 消息，具体内容看后端要求，通常是字符串 'ping' 或 JSON '{ "op": "ping" }'
      socket.value.send("ping");
    }
  }, 15000); // 建议 15-30 秒一次
};

const stopHeartbeat = () => {
  clearInterval(heartbeatTimer);
};

const connectWebSocket = (symbols) => {
  // 如果是重连调用（不传参数），则使用上次的币种
  if (!symbols && lastSymbols.length > 0) {
    symbols = lastSymbols;
  } else if (symbols) {
    lastSymbols = symbols;
  } else {
    return; // 无币种可订阅
  }

  // 关闭旧连接
  isManualClose = true; // 标记为手动关闭，防止立刻触发 onclose 重连
  if (socket.value) {
    socket.value.close();
  }
  clearTimeout(reconnectTimer);
  stopHeartbeat();

  // 构造参数
  const symbolStr = symbols.map(s => s.toLowerCase()).join('/');
  if (!symbolStr) return;

  const wsUrl = `ws://localhost:8080/ws/kline/?symbol=${symbolStr}`;
  console.log('Connecting WS:', wsUrl);

  try {
    isManualClose = false; // 重置标记，准备开始新连接
    socket.value = new WebSocket(wsUrl);

    socket.value.onopen = () => {
      console.log('WS Connected');
      startHeartbeat(); // 连接成功，开启心跳
    };

    socket.value.onmessage = (event) => {
      try {
        const msg = JSON.parse(event.data);
        // 如果收到 pong 消息，可以忽略
        if (msg === 'pong' || msg.op === 'pong') return;

        const data = msg.data || msg;
        const symbol = data.s || data.symbol;
        if (!symbol) return;

        const item = listData.value.find(i =>
          i.name && i.name.toUpperCase() === symbol.toUpperCase()
        );

        if (item) {
          // 1. 实时更新价格
          let newPrice = data.c || data.p || (data.k ? data.k.c : null);
          if (newPrice) {
            item.price = newPrice;
            item.cny = (parseFloat(newPrice) * 7.25).toFixed(2);
          }

          // 2. 实时更新涨跌幅
          let newChange = data.P || data.trend;
          if (newChange) {
            item.change = parseFloat(newChange).toFixed(2);
            const isUp = parseFloat(newChange) >= 0;
            item.btnClass = isUp ? 'btn-green' : 'btn-red';
            item.chartColor = isUp ? '#2EBD85' : '#F6465D';
          }
        }
      } catch (e) {
        // console.error("WS Message Error:", e);
      }
    };

    socket.value.onclose = (e) => {
      stopHeartbeat();
      // 如果不是手动切换Tab导致的关闭，则尝试重连
      if (!isManualClose) {
        console.log('WS Disconnected unexpectedly. Reconnecting in 3s...');
        reconnectTimer = setTimeout(() => {
          connectWebSocket(); // 尝试重连
        }, 3000);
      }
    };

    socket.value.onerror = (err) => {
      console.warn("WS Connection Error:", err);
      // error 后通常会自动触发 close，逻辑交给 onclose 处理
    };
  } catch (e) {
    console.error("WS Create Error:", e);
    // 创建失败也尝试重连
    reconnectTimer = setTimeout(() => {
      connectWebSocket();
    }, 5000);
  }
};

// --- 5. 真实接口请求封装 ---
const fetchData = async (tab, pageNum) => {
  try {
    if (tab !== 'spot') return [];
    const res = await TradingPair({
      type: tab,
      pageNum: pageNum,
      pageSize: PAGE_SIZE
    });

    if (!res || !res.list) return [];

    return res.list.map(item => {
      const trendVal = parseFloat(item.trend || 0);
      const isUp = trendVal >= 0;
      const paths = generateChartPaths(isUp);
      const iconKey = item.base_coin;

      return {
        id: item.id,
        name: item.symbol,
        symbol: item.name,
        price: item.current_price,
        cny: (parseFloat(item.current_price) * 7.25).toFixed(2),
        change: trendVal.toFixed(2),
        iconUrl: item.logo,
        svgIcon: localIcons[iconKey] || null,
        base_coin_char: item.base_coin ? item.base_coin[0] : '?',
        chartLine: paths.linePath,
        chartFill: paths.fillPath,
        chartColor: isUp ? '#2EBD85' : '#F6465D',
        btnClass: isUp ? 'btn-green' : 'btn-red'
      };
    });
  } catch (error) {
    console.error("加载数据失败:", error);
    return [];
  }
};

// --- 6. 核心逻辑：数据加载 ---
const onLoad = async () => {
  if (loading.value || finished.value) return;

  loading.value = true;

  const data = await fetchData(currentTab.value, page.value);

  // console.log(`Tab: ${currentTab.value}, Page: ${page.value}, Loaded: ${data.length}`);

  if (data.length === 0) {
    finished.value = true;
  } else {
    listData.value.push(...data);
    page.value++;

    if (data.length < PAGE_SIZE) {
      finished.value = true;
    }
    console.log(listData.value,'llll');
    const allSymbols = listData.value.map(item => item.name);
    if (allSymbols.length > 0) {
      connectWebSocket(allSymbols);
    }
  }
  loading.value = false;
};

// 监听 Tab 切换
watch(currentTab, () => {
  isManualClose = true; // 切换前标记手动关闭
  if (socket.value) {
    socket.value.close();
    socket.value = null;
  }
  // 清理重连定时器，避免在切换Tab期间触发上一个Tab的重连
  clearTimeout(reconnectTimer);

  listData.value = [];
  page.value = 1;
  finished.value = false;
  loading.value = false;
  if (scrollContainer.value) scrollContainer.value.scrollTop = 0;
  onLoad();
});

const handleScroll = (e) => {
  const { scrollTop, clientHeight, scrollHeight } = e.target;
  if (scrollTop + clientHeight >= scrollHeight - 100) {
    onLoad();
  }
};

// 处理页面可见性变化（切后台再回来）
const handleVisibilityChange = () => {
  if (document.visibilityState === 'visible') {
    // 如果回来发现连接断了，立即重连
    if (!socket.value || socket.value.readyState === WebSocket.CLOSED) {
      console.log('Page visible, checking WS connection...');
      connectWebSocket();
    }
  }
};

onMounted(() => {
  onLoad();
  document.addEventListener('visibilitychange', handleVisibilityChange);
});

onUnmounted(() => {
  document.removeEventListener('visibilitychange', handleVisibilityChange);
  isManualClose = true;
  if (socket.value) socket.value.close();
  clearTimeout(reconnectTimer);
  stopHeartbeat();
});

// 格式化工具函数
const formatPrice = (val) => {
  if(!val) return '0.00';
  const num = parseFloat(val);
  return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 });
};
const formatCNY = (val) => {
  if(!val) return '0.00';
  const num = parseFloat(val);
  return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};
</script>

<template>
  <div class="market-page">
    <svg width="0" height="0" style="position:absolute;">
      <defs>
        <linearGradient id="chart-grad-up" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:#2EBD85;stop-opacity:0.2" />
          <stop offset="100%" style="stop-color:#2EBD85;stop-opacity:0" />
        </linearGradient>
        <linearGradient id="chart-grad-down" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:#F6465D;stop-opacity:0.2" />
          <stop offset="100%" style="stop-color:#F6465D;stop-opacity:0" />
        </linearGradient>
      </defs>
    </svg>

    <div class="sticky-header">
      <div class="top-bar">
        <div class="tabs-wrapper">
          <div
            v-for="tab in tabs"
            :key="tab.key"
            @click="currentTab = tab.key"
            class="tab-item"
            :class="{ active: currentTab === tab.key }"
          >
            {{ tab.label }}
            <div v-if="currentTab === tab.key" class="active-indicator"></div>
          </div>
        </div>
        <div class="search-icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#707A8A" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
        </div>
      </div>

      <!-- 表头增加排序图标 -->
      <div class="table-header">
        <div class="col col-left">
          交易对
          <div class="sort-box">
             <div class="sort-up"></div>
             <div class="sort-down"></div>
          </div>
        </div>
        <div class="col col-center">
          最新价
          <div class="sort-box">
             <div class="sort-up"></div>
             <div class="sort-down"></div>
          </div>
        </div>
        <div class="col col-right">
          今日涨跌幅
          <div class="sort-box">
             <div class="sort-up"></div>
             <div class="sort-down"></div>
          </div>
        </div>
      </div>
    </div>

    <div
      class="list-container"
      ref="scrollContainer"
      @scroll="handleScroll"
    >
      <div
        v-for="coin in listData"
        :key="coin.id"
        class="list-item"
        @click="router.push({ path: '/marketDetails', query: { id: coin.id, type: coin.name.toLowerCase()} })"
      >
        <div class="col col-left coin-info">
          <div class="coin-icon-wrapper">
            <img v-if="coin.iconUrl" :src="coin.iconUrl" class="real-icon-img" alt="icon" />
            <svg v-else-if="coin.svgIcon" viewBox="0 0 32 32" class="real-icon" v-html="coin.svgIcon"></svg>
            <div v-else class="placeholder-icon">{{ coin.base_coin_char }}</div>
          </div>
          <div class="text-group">
            <div class="name-row">{{ coin.name }}</div>
            <div class="symbol-row">{{ coin.symbol }}</div>
          </div>
        </div>

        <div class="col col-center chart-box">
          <svg width="60" height="24" viewBox="0 0 60 24">
            <path :d="coin.chartFill" :fill="coin.change >= 0 ? 'url(#chart-grad-up)' : 'url(#chart-grad-down)'" />
            <path :d="coin.chartLine" fill="none" :stroke="coin.chartColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
          </svg>
        </div>

        <div class="col col-right price-info">
          <div class="price transition-colors duration-300" :class="coin.change >= 0 ? 'text-[#2EBD85]' : 'text-[#F6465D]'">
            {{ formatPrice(coin.price) }}
          </div>
          <div class="cny">¥ {{ formatCNY(coin.cny) }}</div>
        </div>
        <div>
          <button class="change-btn transition-colors duration-300" :class="coin.btnClass">
            {{ coin.change >= 0 ? '+' : '' }}{{ coin.change }}%
          </button>
        </div>
      </div>

      <!-- 底部状态区 -->
      <div class="loading-state">
        <div v-if="loading" class="spinner-container">
          <div class="spinner"></div>
          <span class="loading-text">加载中...</span>
        </div>
        <div v-else-if="finished && listData.length > 0" class="no-more-text">
          - 没有更多了 -
        </div>
        <div v-else-if="finished && listData.length === 0" class="empty-state">
          暂无数据
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
/* 基础重置 */
* { box-sizing: border-box; }

.market-page {
  display: flex;
  flex-direction: column;
  height: 100%;
  background-color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
  color: #1E2329;
}

.sticky-header {
  position: sticky;
  top: 0;
  background-color: #fff;
  z-index: 10;
  padding: 12px 16px 0;
}

.top-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.tabs-wrapper {
  display: flex;
  gap: 28px;
  align-items: flex-end;
}

.tab-item {
  position: relative;
  font-size: 16px;
  color: #707A8A;
  font-weight: 500;
  padding-bottom: 8px;
  cursor: pointer;
  transition: all 0.2s;
  line-height: 24px;
}

.tab-item.active {
  font-size: 20px;
  font-weight: 600;
  color: #1E2329;
}

.active-indicator {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 16px;
  height: 3px;
  background-color: #1E2329;
  border-radius: 2px;
}

.table-header {
  display: flex;
  font-size: 12px;
  color: #707A8A;
  padding-bottom: 8px;
}

.col { display: flex; }
.col-left { width: 52%; justify-content: flex-start; align-items: center; }
.col-center { width: 25%; justify-content: center; align-items: center; margin-left: 10px; }
/* 修正右侧列样式，支持排序图标 */
.col-right { width: 37%; justify-content: flex-end; align-items: center; }

/* 排序小三角 */
.sort-box {
  display: flex;
  flex-direction: column;
  margin-left: 4px;
  gap: 2px;
  cursor: pointer;
}
.sort-up {
  width: 0;
  height: 0;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-bottom: 4px solid #B7BDC6;
}
.sort-down {
  width: 0;
  height: 0;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-top: 4px solid #B7BDC6;
}

.list-container {
  flex: 1;
  overflow-y: auto;
  padding: 0 15px 80px;
}

.list-item {
  display: flex;
  padding: 16px 0;
  border-bottom: 1px solid #F0F3F5;
  align-items: center;
}

.coin-icon-wrapper {
  width: 28px; height: 28px; margin-right: 8px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.real-icon { width: 100%; height: 100%; }
.real-icon-img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.placeholder-icon {
  width: 100%; height: 100%; background: #F0F3F5; border-radius: 50%;
  color: #707A8A; display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: bold;
}

.text-group { display: flex; flex-direction: column; }
.name-row { font-size: 14px; font-weight: 600; color: #1E2329; margin-bottom: 2px; }
.symbol-row { font-size: 12px; color: #707A8A; }

.chart-box svg { overflow: visible; }

.price-info.col-right {
  display: inline-block; text-align: right; margin-right: 8px;
}
.price { font-size: 14px; font-weight: 600; }
.cny { font-size: 11px; color: #707A8A; margin-bottom: 4px; transform: scale(0.95); transform-origin: right center; }

.change-btn {
  width: 72px; height: 32px; border: none; border-radius: 4px;
  color: #fff; font-size: 13px; font-weight: 500;
  display: flex; align-items: center; justify-content: center; margin-top: 2px;
}
.btn-green { background-color: #2EBD85; }
.btn-red { background-color: #F6465D; }

.loading-state {
  text-align: center;
  padding: 20px 0;
  color: #999;
  font-size: 12px;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 80px;
  width: 100%;
}

.spinner-container {
  display: flex;
  align-items: center;
  gap: 8px;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid #e0e0e0;
  border-top-color: #707A8A;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

.loading-text {
  font-size: 12px;
  color: #999;
}

.no-more-text {
  color: #555;
  font-size: 13px;
  padding: 8px 16px;
  background-color: #f0f0f0;
  border-radius: 20px;
}

.empty-state {
  color: #999;
  font-size: 14px;
  padding-top: 40px;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.text-[#2EBD85] { color: #2EBD85; }
.text-[#F6465D] { color: #F6465D; }
</style>