import type { ChatMessage, UserAdminInfo, ViewerCardState } from '@/app/room/_components/types'
import type { Dispatch, MutableRefObject, SetStateAction } from 'react'

export type ModRoleStateRefs = {
    streamUserId: string
    currentUserId?: string | null
    isOwnStream: boolean
    modUserIdsRef: MutableRefObject<Set<string>>
    superAdminUserIdsRef: MutableRefObject<Set<string>>
    isModeratorRef?: MutableRefObject<boolean>
}

export type ModRoleStateSetters = {
    setModUserIds: Dispatch<SetStateAction<Set<string>>>
    setIsMod?: Dispatch<SetStateAction<boolean>>
    setMessages: Dispatch<SetStateAction<ChatMessage[]>>
    setPinnedMessage?: Dispatch<SetStateAction<ChatMessage | null>>
    setUserAdminInfo?: Dispatch<SetStateAction<UserAdminInfo | null>>
    setChatViewerCard?: Dispatch<SetStateAction<ViewerCardState | null>>
}

function patchMessagesModAdded(
    prev: ChatMessage[],
    addedUserId: string,
    streamUserId: string,
    superAdminUserIds: Set<string>
): ChatMessage[] {
    return prev.map((msg) => {
        if (msg.userId !== addedUserId || msg.userType === 'manager') return msg
        if (msg.userId === streamUserId || superAdminUserIds.has(addedUserId)) return msg
        return { ...msg, userType: 'manager' as const }
    })
}

function patchMessagesModRemoved(
    prev: ChatMessage[],
    removedUserId: string,
    streamUserId: string,
    superAdminUserIds: Set<string>
): ChatMessage[] {
    return prev.map((msg) => {
        if (msg.userId !== removedUserId || msg.userType !== 'manager') return msg
        if (msg.userId === streamUserId) {
            return { ...msg, userType: 'streamer' as const }
        }
        if (superAdminUserIds.has(removedUserId)) {
            return { ...msg, userType: 'superAdmin' as const }
        }
        return { ...msg, userType: undefined }
    })
}

function patchPinnedModAdded(
    prev: ChatMessage | null,
    addedUserId: string,
    streamUserId: string,
    superAdminUserIds: Set<string>
): ChatMessage | null {
    if (!prev || prev.userId !== addedUserId || prev.userType === 'manager') return prev
    if (prev.userId === streamUserId || superAdminUserIds.has(addedUserId)) return prev
    return { ...prev, userType: 'manager' as const }
}

function patchPinnedModRemoved(
    prev: ChatMessage | null,
    removedUserId: string,
    streamUserId: string,
    superAdminUserIds: Set<string>
): ChatMessage | null {
    if (!prev || prev.userId !== removedUserId || prev.userType !== 'manager') return prev
    if (prev.userId === streamUserId) {
        return { ...prev, userType: 'streamer' as const }
    }
    if (superAdminUserIds.has(removedUserId)) {
        return { ...prev, userType: 'superAdmin' as const }
    }
    return { ...prev, userType: undefined }
}

/** 指定 Mod 後同步本地 mod 集合、訊息與 ViewerCard 圖示 */
export function applyModAdded(
    refs: ModRoleStateRefs,
    setters: ModRoleStateSetters,
    addedUserId: string
) {
    const id = String(addedUserId ?? '').trim()
    if (!id) return

    setters.setModUserIds((prev) => {
        const next = new Set(prev)
        next.add(id)
        refs.modUserIdsRef.current = next
        return next
    })

    if (id === refs.currentUserId) {
        setters.setIsMod?.(true)
        if (refs.isModeratorRef) refs.isModeratorRef.current = true
    }

    setters.setUserAdminInfo?.((prev) => {
        if (prev && prev.userId === id) {
            return { ...prev, isMod: true }
        }
        return prev
    })

    setters.setMessages((prev) =>
        patchMessagesModAdded(prev, id, refs.streamUserId, refs.superAdminUserIdsRef.current)
    )

    setters.setPinnedMessage?.((prev) =>
        patchPinnedModAdded(prev, id, refs.streamUserId, refs.superAdminUserIdsRef.current)
    )

    setters.setChatViewerCard?.((prev) => {
        if (!prev || prev.user.id !== id) return prev
        if (prev.user.userType === 'manager') return prev
        return { ...prev, user: { ...prev.user, userType: 'manager' as const } }
    })
}

/** 移除 Mod 後同步本地 mod 集合、訊息與 ViewerCard 圖示 */
export function applyModRemoved(
    refs: ModRoleStateRefs,
    setters: ModRoleStateSetters,
    removedUserId: string
) {
    const id = String(removedUserId ?? '').trim()
    if (!id) return

    setters.setModUserIds((prev) => {
        const next = new Set(prev)
        next.delete(id)
        refs.modUserIdsRef.current = next
        return next
    })

    if (id === refs.currentUserId) {
        setters.setIsMod?.(false)
        if (refs.isModeratorRef) {
            refs.isModeratorRef.current =
                refs.isOwnStream || refs.superAdminUserIdsRef.current.has(refs.currentUserId || '')
        }
    }

    setters.setUserAdminInfo?.((prev) => {
        if (prev && prev.userId === id) {
            return { ...prev, isMod: false }
        }
        return prev
    })

    setters.setMessages((prev) =>
        patchMessagesModRemoved(prev, id, refs.streamUserId, refs.superAdminUserIdsRef.current)
    )

    setters.setPinnedMessage?.((prev) =>
        patchPinnedModRemoved(prev, id, refs.streamUserId, refs.superAdminUserIdsRef.current)
    )

    setters.setChatViewerCard?.((prev) => {
        if (!prev || prev.user.id !== id) return prev
        if (id === refs.streamUserId) {
            return { ...prev, user: { ...prev.user, userType: 'streamer' as const } }
        }
        if (refs.superAdminUserIdsRef.current.has(id)) {
            return { ...prev, user: { ...prev.user, userType: 'superAdmin' as const } }
        }
        return { ...prev, user: { ...prev.user, userType: undefined } }
    })
}
