import { ref, reactive } from 'vue'
import { useWebSocket } from '@vueuse/core'
import { neonColors } from './td-color'

type EventHandler = (data: any) => void

export function useSocketBus(deviceCode: string) {
  const url = `${import.meta.env.VITE_BASE_URL}/ws/${deviceCode}`
  // const url = `ws://192.168.188.149:8080/ws/${deviceCode}`

  // 响应式状态
  const status = ref<'CONNECTING' | 'OPEN' | 'CLOSED'>('CLOSED')
  const messages = ref<any[]>([])

  // 事件总线
  const events: Record<string, EventHandler[]> = reactive({})

  // 创建 WebSocket
  const { ws, open, close, send } = useWebSocket(url, {
    immediate: false,
    autoReconnect: {
      retries: 5,
      delay: 1000
    },
    onConnected(_ws) {
      console.log('✅ WebSocket 已连接')
      status.value = 'OPEN'
    },
    onDisconnected() {
      console.log('🔌 WebSocket 已断开')
      status.value = 'CLOSED'
    },
    onMessage(_ws, event) {
      try {
        const msg = JSON.parse(event.data)
        messages.value.push(msg)
        if (msg.event && events[msg.event]) {
          events[msg.event].forEach((cb) => cb(msg.data))
        }

        anyHandlers.forEach((cb) => cb(msg))
      } catch (err) {
        console.warn('非 JSON 消息:', event.data)
      }
    }
  })

  const anyHandlers: EventHandler[] = reactive([])

  // 注册所有事件回调
  function onAny(cb: EventHandler) {
    anyHandlers.push(cb)
  }

  // 注册事件
  function on(eventName: string, cb: EventHandler) {
    if (!events[eventName]) events[eventName] = []
    events[eventName].push(cb)
  }

  // 注销事件
  function off(eventName: string, cb?: EventHandler) {
    if (!cb) {
      events[eventName] = []
    } else {
      events[eventName] = (events[eventName] || []).filter((fn) => fn !== cb)
    }
  }

  // 发送带事件名的消息
  function sendEvent(eventName: string, data: any) {
    if (ws.value?.readyState === WebSocket.OPEN) {
      send(JSON.stringify({ event: eventName, data }))
    } else {
      console.warn('⚠️ WebSocket 未连接')
    }
  }

  return { ws, status, messages, on, off, sendEvent, open, close, onAny }
}

export const formatIotValue = (val: any) => {
  if (val === null || val === undefined) return { value: '0', isText: true }
  const strVal = String(val)

  if (!/\d/.test(strVal)) {
    return { value: strVal, isText: true }
  }

  const match = strVal.match(/^(-?\d+(?:\.\d+)?)(.*)$/)

  if (match) {
    return {
      value: match[1],
      suffix: match[2] || '',
      isText: false
    }
  }
  return { value: strVal, isText: true }
}

export interface HeaderItem {
  label: string
  key: string
  judgment?: boolean
}

export interface Dimensions {
  identifier: string
  name: string
  value: string | number
  color: string
  bgHover: string
  bgActive: string
  response?: boolean
  suffix?: string
  isText?: boolean
  minValue?: number
  maxValue?: number
  id?: number
}

export function hexToRgba(hex: string, alpha: number) {
  const r = parseInt(hex.slice(1, 3), 16)
  const g = parseInt(hex.slice(3, 5), 16)
  const b = parseInt(hex.slice(5, 7), 16)
  return `rgba(${r}, ${g}, ${b}, ${alpha})`
}

export function normalizeRangeValue(value: unknown) {
  if (value === null || value === undefined || value === '') return undefined

  const numberValue = Number(value)

  return Number.isFinite(numberValue) ? numberValue : undefined
}

export function formatChartValue(value: unknown) {
  const numberValue = Number(value)

  if (!Number.isFinite(numberValue)) return '--'

  return Number.isInteger(numberValue) ? `${numberValue}` : numberValue.toFixed(2)
}

export type RawDimension = Omit<Dimensions, 'color' | 'bgHover' | 'bgActive'>

export interface IotTdItem {
  identifier: string
  modelName: string
  modelOrder?: number
  value: unknown
  alarmSettingId?: number
  maxValue?: unknown
  minValue?: unknown
}

export function mapToDimension(item: IotTdItem): RawDimension {
  const { value, suffix, isText } = formatIotValue(item.value)

  return {
    identifier: item.identifier,
    name: item.modelName,
    value,
    suffix,
    isText,
    response: false,
    id: item.alarmSettingId,
    maxValue: item.alarmSettingId ? normalizeRangeValue(item.maxValue) : undefined,
    minValue: item.alarmSettingId ? normalizeRangeValue(item.minValue) : undefined
  }
}

export function withDisplayStyle(item: RawDimension, index: number): Dimensions {
  const color = neonColors[index % neonColors.length]

  return {
    ...item,
    color,
    bgHover: hexToRgba(color, 0.08),
    bgActive: hexToRgba(color, 0.12)
  }
}

export interface RangeSettingDraft {
  name: string
  identifier: string
  color: string
  minValue?: number
  maxValue?: number
}
