import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { MarketType, CoinDetail, ChartRange, MarketItem } from '@/types'
import { useCoinsStore } from './coins'
import { useSpotStore } from './spot'

const SPOT_WS_URL = import.meta.env.VITE_WS_SPOT_URL as string

export const useMarketStore = defineStore('market', () => {
  const coinsStore = useCoinsStore()
  const spotStore  = useSpotStore()

  // ── State ──────────────────────────────────────────
  const activeTab = ref<MarketType>('futures')
  const searchQuery = ref('')

  // ── 现货实时价格缓存 ────────────────────────────────
  interface SpotTick {
    close: number; open: number; high: number; low: number; turnover: number
  }
  const spotTicks = ref<Map<string, SpotTick>>(new Map())
  const spotLoading = ref(false)
  let spotWs: WebSocket | null = null
  let spotWsDestroyed = false
  let spotPingTimer: ReturnType<typeof setInterval> | null = null
  let spotLastMsgTs = 0

  function spotSymSlug(sym: string) {
    return sym.toUpperCase().replace(/[/\s-]/g, '').toLowerCase()
  }

  function spotTickerChannel(sym: string) {
    return `market_${spotSymSlug(sym)}_ticker`
  }

  function stopSpotWs() {
    spotWsDestroyed = true
    if (spotPingTimer !== null) { clearInterval(spotPingTimer); spotPingTimer = null }
    if (spotWs) {
      if (spotWs.readyState === WebSocket.OPEN && spotStore.symbolList.length > 0) {
        for (const s of spotStore.symbolList) {
          spotWs.send(JSON.stringify({ event: 'unsub', params: { channel: spotTickerChannel(s.symbol) } }))
        }
      }
      spotWs.onclose = null
      spotWs.close()
      spotWs = null
    }
  }

  function startSpotWs(symbols: string[]) {
    if (!symbols.length || !SPOT_WS_URL) return
    stopSpotWs()
    spotWsDestroyed = false
    spotWs = new WebSocket(SPOT_WS_URL)
    spotWs.onopen = () => {
      for (const s of symbols) {
        spotWs!.send(JSON.stringify({ event: 'sub', params: { channel: spotTickerChannel(s) } }))
      }
      spotLastMsgTs = Date.now()
      spotPingTimer = setInterval(() => {
        if (Date.now() - spotLastMsgTs > 30_000) {
          stopSpotWs()
          if (!spotWsDestroyed) startSpotWs(symbols)
          return
        }
      }, 15_000)
    }
    spotWs.onmessage = (e) => {
      spotLastMsgTs = Date.now()
      let msg: any
      try { msg = JSON.parse(e.data) } catch { return }
      if (msg.ping !== undefined) {
        spotWs?.send(JSON.stringify({ pong: msg.ping }))
        return
      }
      const ch: string = msg.channel ?? msg.ch ?? ''
      const rawTick = msg.tick ?? msg.data
      const tick = rawTick && !Array.isArray(rawTick) && typeof rawTick === 'object' ? rawTick : null
      if (!ch.includes('_ticker') || !tick) return
      const sym = symbols.find(s => spotTickerChannel(s) === ch)
      if (!sym) return
      spotTicks.value.set(sym, {
        close: parseFloat(String((tick as any).close ?? (tick as any).last ?? (tick as any).price ?? 0)),
        open: parseFloat(String((tick as any).open ?? 0)),
        high: parseFloat(String((tick as any).high ?? 0)),
        low: parseFloat(String((tick as any).low ?? 0)),
        turnover: parseFloat(String((tick as any).amount ?? (tick as any).quoteVolume ?? 0)),
      })
    }
    spotWs.onerror = () => {}
    spotWs.onclose = () => {
      if (spotPingTimer !== null) { clearInterval(spotPingTimer); spotPingTimer = null }
      if (spotWsDestroyed) return
      setTimeout(() => startSpotWs(symbols), 3000)
    }
  }

  async function loadSpotSymbols() {
    if (spotStore.symbolList.length > 0) {
      void spotStore.fetchCoinIcons()
      startSpotWs(spotStore.symbolList.map(s => s.symbol))
      return
    }
    spotLoading.value = true
    try {
      await spotStore.loadSymbols()
      void spotStore.fetchCoinIcons()
      if (spotStore.symbolList.length > 0) {
        startSpotWs(spotStore.symbolList.map(s => s.symbol))
      }
    } catch { /* silent */ } finally {
      spotLoading.value = false
    }
  }

  // list is derived from coins store (real-time via WebSocket)
  const futuresList = computed<MarketItem[]>(() =>
    coinsStore.coins.map(c => {
      const price = parseFloat(c.close)
      const open = parseFloat(c.open)
      const change24h = open > 0 ? ((price - open) / open) * 100 : parseFloat(c.chg) * 100
      return {
        symbol: c.symbol,
        name: c.name,
        type: 'futures' as const,
        icon: c.icon,
        price,
        change24h,
        high24h: parseFloat(c.high),
        low24h: parseFloat(c.low),
        volume24h: parseFloat(c.turnover),
      }
    })
  )

  const spotList = computed<MarketItem[]>(() =>
    spotStore.symbolList.map(s => {
      const tick = spotTicks.value.get(s.symbol)
      const price  = tick?.close ?? 0
      const open   = tick?.open  ?? 0
      const change24h = open > 0 ? ((price - open) / open) * 100 : 0
      const base = s.base.toLowerCase()
      const COIN_ICONS: Record<string, string> = {
        btc: '/coins/btc.png', eth: '/coins/eth.png', bnb: '/coins/bnb.png',
        sol: '/coins/sol.png', xrp: '/coins/xrp.png', ada: '/coins/ada.png',
        doge: '/coins/doge.png', ltc: '/coins/ltc.png', trx: '/coins/trx.png',
        dot: '/coins/dot.png', link: '/coins/link.png',
      }
      const fromSymbolList = (s.icon && s.icon.trim()) || ''
      const fromCoinMap = spotStore.coinIconMap.get(s.base.toUpperCase()) ?? ''
      const localPng = COIN_ICONS[base] ?? ''
      return {
        symbol: `${s.base}/${s.quote}`,
        name: s.base,
        type: 'spot' as const,
        icon: fromSymbolList || fromCoinMap || localPng,
        price,
        change24h,
        high24h: tick?.high ?? 0,
        low24h:  tick?.low  ?? 0,
        volume24h: tick?.turnover ?? 0,
      }
    })
  )

  const list = computed<MarketItem[]>(() => [...futuresList.value, ...spotList.value])

  const loading = computed(() => coinsStore.loading || spotLoading.value)
  const error = ref('')

  const currentCoin = ref<CoinDetail | null>(null)
  const chartRange = ref<ChartRange>('1m')
  const coinLoading = ref(false)

  // ── Getters ────────────────────────────────────────
  const filteredList = computed(() => {
    let result =
      activeTab.value === 'futures' ? futuresList.value : spotList.value

    if (searchQuery.value.trim()) {
      const q = searchQuery.value.trim().toUpperCase()
      result = result.filter(item => item.symbol.toUpperCase().includes(q))
    }

    return result
  })

  const hotList = computed(() => futuresList.value.slice(0, 3))

  const topVolumeList = computed(() =>
    [...futuresList.value].sort((a, b) => b.volume24h - a.volume24h).slice(0, 3)
  )

  // ── Actions ────────────────────────────────────────
  async function fetchList() {
    error.value = ''
    try {
      await coinsStore.fetchCoins()
    } catch (e) {
      error.value = e instanceof Error ? e.message : '获取行情失败'
    }
  }

  function setTab(tab: MarketType) {
    activeTab.value = tab
    if (tab === 'spot') {
      // 切到现货：取消合约行情订阅
      coinsStore.stopLivePrices()
      void loadSpotSymbols()
      return
    }
    // 切到合约：取消现货行情订阅并恢复合约行情
    stopSpotWs()
    void coinsStore.fetchCoins()
  }

  function setSearch(query: string) {
    searchQuery.value = query
  }

  async function fetchCoinDetail(symbol: string) {
    coinLoading.value = true
    currentCoin.value = null
    try {
      const coin = coinsStore.coins.find(c => c.symbol === symbol)
      if (coin) {
        const price = parseFloat(coin.close || '0')
        const open = parseFloat(coin.open || '0')
        currentCoin.value = {
          symbol: coin.symbol,
          name: coin.name,
          icon: coin.icon ?? '',
          marketCap: '--',
          circulatingSupply: '--',
          totalSupply: '--',
          allTimeHigh: 0,
          currentPrice: price,
          priceChange: open > 0 ? price - open : 0,
          priceChangePct: open > 0 ? ((price - open) / open) * 100 : 0,
          stats: [],
          chartData: [],
        }
      }
    } finally {
      coinLoading.value = false
    }
  }

  function setChartRange(range: ChartRange) {
    chartRange.value = range
  }

  // 离开行情页时统一关闭，避免顶部导航切页后残留订阅
  function stopAllWs() {
    stopSpotWs()
    coinsStore.stopLivePrices()
  }

  // ── Return ALL state ───────────────────────────────
  return {
    list,
    activeTab,
    searchQuery,
    loading,
    error,
    currentCoin,
    chartRange,
    coinLoading,
    filteredList,
    hotList,
    topVolumeList,
    fetchList,
    fetchCoinDetail,
    setTab,
    setSearch,
    setChartRange,
    loadSpotSymbols,
    stopSpotWs,
    stopAllWs,
  }
})
