import { decryptWsPayload, encryptWsPayload } from '@/utils/wsCrypto'
import {
    isStreamLiveByLifecycleStatus,
    isStreamOfflineByLifecycleStatus,
} from '@/lib/streams/lifecycleStatus'

export type { StreamStatusPayload } from '@/lib/streams/streamStatusPayload'
import type { StreamStatusPayload } from '@/lib/streams/streamStatusPayload'

export type StreamViewersUpdatePayload = {
    roomId: string
    viewers: number
}

/** 訂閱全部房間直播狀態（連線後須 send subscribe） */
export function buildStreamsWsUrl(): string {
    if (typeof window === 'undefined') return ''

    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
    const wsPort = process.env.NEXT_PUBLIC_WS_PORT || '3001'
    const defaultUrl = isLocal
        ? `ws://${window.location.hostname}:${wsPort}/streams`
        : `${protocol}//${window.location.host}/streams`
    if (isLocal) return defaultUrl
    const fromEnv = process.env.NEXT_PUBLIC_WS_URL?.trim()
    if (fromEnv) return fromEnv.replace(/\/(ws|chat)\/?$/, '/streams')
    return defaultUrl
}

export function sendStreamsWs(ws: WebSocket, payload: Record<string, unknown>) {
    ws.send(encryptWsPayload(payload))
}

/** 訂閱房間；同一房間全域 refcount +1，CF API 只輪詢一次 */
export function sendStreamsSubscribe(ws: WebSocket, roomIds: string[]) {
    const ids = roomIds.map((id) => String(id).trim()).filter(Boolean)
    if (ids.length === 0) return
    sendStreamsWs(ws, { type: 'subscribe', roomIds: ids })
}

/** 訂閱所有有 m3u8 的房間（首頁列表用） */
export function sendStreamsSubscribeAll(ws: WebSocket) {
    sendStreamsWs(ws, { type: 'subscribe', all: true })
}

export function sendStreamsUnsubscribe(ws: WebSocket, roomIds: string[]) {
    sendStreamsWs(ws, { type: 'unsubscribe', roomIds })
}

export type StreamsCatalogPayload = {
    rooms: Array<{
        roomId: string
        publicId: string
        streamerName: string
        title: string
        category: string | null
        thumbnail?: string
        src?: string
        avatar?: string
        likeCount?: number
    }>
}

export type ParsedStreamsWsMessage = {
    type: string
    data?: Record<string, unknown>
    error?: string
    message?: string
}

export function parseStreamsWsMessage(data: string): ParsedStreamsWsMessage | null {
    const raw = decryptWsPayload(data)
    if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null
    const row = raw as ParsedStreamsWsMessage
    return typeof row.type === 'string' ? row : null
}

export function getStreamsSnapshotList(
    data: Record<string, unknown> | undefined
): StreamStatusPayload[] | undefined {
    const streams = data?.streams
    return Array.isArray(streams) ? (streams as StreamStatusPayload[]) : undefined
}

export { parseStreamStatusPayload } from './parseStreamStatusPayload'

export function getStreamsCatalogRooms(
    data: Record<string, unknown> | undefined
): StreamsCatalogPayload['rooms'] | undefined {
    const rooms = data?.rooms
    return Array.isArray(rooms) ? (rooms as StreamsCatalogPayload['rooms']) : undefined
}

export function sendStreamsSnapshotRequest(ws: WebSocket) {
    sendStreamsWs(ws, { type: 'get_streams_snapshot' })
}

export function isStreamViewersUpdatePayload(
    data: unknown
): data is StreamViewersUpdatePayload {
    if (!data || typeof data !== 'object') return false
    const row = data as StreamViewersUpdatePayload
    return typeof row.roomId === 'string' && typeof row.viewers === 'number'
}

export function findStreamStatusForRoom(
    streams: StreamStatusPayload[] | undefined,
    roomId: string,
): StreamStatusPayload | undefined {
    if (!streams?.length) return undefined
    return streams.find((s) => s.roomId === roomId)
}

/** 依 CF status 判斷是否開播（見 lifecycleStatus.ts） */
export function isStreamPayloadLive(payload: StreamStatusPayload | null | undefined): boolean {
    if (!payload) return false
    if (payload.cfHasHistory === true) return false
    if (payload.live === false) return false
    if (isStreamOfflineByLifecycleStatus(payload.status)) return false
    return isStreamLiveByLifecycleStatus(payload.status)
}
