import { isStreamLiveByLifecycleStatus } from '@/lib/streams/lifecycleStatus'
import {
    parseRoomStreamCategory,
    roomStreamCategoryToTagIds,
} from '@/lib/streams/roomStreamCategory'
import { notFound, redirect } from 'next/navigation'
import { cookies } from 'next/headers'
import { getDb } from '@/server/db'
import { fetchUserActiveAvatarFrame } from '@/server/avatarFrames/query'
import { fetchUserGroups, type UserGroupListItem } from '@/server/groups/fetchUserGroups'
import { USER_AUTH_SQL } from '@/server/userAuthSql'
import { resolveUserProfileRoute } from '@/server/userIdUtils'
import { pickRowNumber, pickRowString, readDisplayName } from '@/server/pgRow'
import { SESSION_ID_COOKIE } from '@/app/_helpers/constants'

export type DbUserRow = {
    id: string
    displayName: string
    avatar: string | null
    banner: string | null
    followersCount: number
    isVerified: number
}

export type DbLiveStreamVodRow = {
    roomId: string
    userId: string
    title: string
    thumbnail: string | null
    viewers: number
    startedAt: string | number | null
    uploadedAt: string | number | null
    category: string | null
    createdAt: string | number | null
}

export type DbLiveRow = {
    roomId: string
    userId: string
    streamStatus: string | null
    title: string | null
    viewers: number
    startedAt: string | number | null
    thumbnail: string | null
    src: string | null
}

export type DbAvatarFrameRow = {
    id: string
    name: string
    image: string
    type: string | null
}

export type DbBoardPostRow = {
    id: string
    userId: string
    created_at_sec: number
    pinned: number
    content: string
    comments: number
    views: number
    thumb: string | null
    thumbCount: number
    displayName: string
    avatar: string | null
}

export type UserPageData = {
    profile: {
        id: string
        /** 個人頁網址路徑用（display_id 或 user_id），與 API 用的 id 可能不同 */
        profileUrlPath: string
        displayName: string
        avatar: string
        banner: string
        description: string
        followersCount: number
        totalViewsCount: number
        isVerified: boolean
        vipLevel: 'none' | 'vip' | 'vvip' | 'svip' | 'royal'
        avatarFrame: {
            id: string
            image: string
            type: 'LOTTIE' | 'IMG'
        } | null
        live?: {
            isLive: boolean
            roomId: string
            title: string
            viewers: number
            startedAt: string
            thumbnail: string
            src?: string
        }
    }
    vodList: Array<{
        id: string
        title: string
        thumb: string
        views: number
        startedAt: string
        startedTs: number
        duration: string
        category: string
        tags: string[]
    }>
    boardPosts: Array<{
        id: string
        authorName: string
        authorAvatar: string
        date: string
        pinned: boolean
        content: string
        comments: number
        views: number
        thumb: string
        thumbCount: number
    }>
    initialIsFollowing: boolean
    initialIsBlocked: boolean
    initialIsBlockedByTarget: boolean
    groups: UserGroupListItem[]
}

export type UserBoardPostItem = UserPageData['boardPosts'][number]

export type FetchUserPageResult =
    | { kind: 'not_found' }
    | { kind: 'post_not_found' }
    | { kind: 'redirect'; redirectTo: string }
    | { kind: 'blocked' }
    | {
          kind: 'ok'
          currentUserId: string | null
          currentUserAvatar: string | null
          data: UserPageData
          selectedPostId?: string
          selectedPost?: UserBoardPostItem
      }

export type LoadUserPageResult = Extract<FetchUserPageResult, { kind: 'blocked' | 'ok' }>

export async function fetchUserPageData(
    userKey: string,
    opts?: { canonicalPathSuffix?: string; postId?: string }
): Promise<FetchUserPageResult> {
    const postId = String(opts?.postId ?? '').trim()
    const pathSuffix =
        opts?.canonicalPathSuffix ??
        (postId ? `/posts/${encodeURIComponent(postId)}` : '')

    const db = await getDb()
    const resolved = await resolveUserProfileRoute(db, userKey)
    if (!resolved) {
        return { kind: 'not_found' }
    }
    if (resolved.shouldRedirect) {
        return {
            kind: 'redirect',
            redirectTo: `/user/${encodeURIComponent(resolved.publicUserId)}${pathSuffix}`,
        }
    }
    const userId = resolved.userId

    let currentUserId: string | null = null
    let currentUserAvatar: string | null = null
    let initialIsBlockedByTarget = false
    try {
        const jar = await cookies()
        const sessionId = jar.get(SESSION_ID_COOKIE)?.value
        if (sessionId) {
            const session = await db.get<Record<string, unknown>>(
                USER_AUTH_SQL.selectSessionUserId,
                [sessionId]
            )
            const sessionUserId = pickRowString(session, 'userId', 'user_id')
            if (sessionUserId) {
                currentUserId = sessionUserId
                const sessionUser = await db.get<Record<string, unknown>>(
                    `SELECT avatar_url AS avatar FROM users WHERE user_id = ?`,
                    [sessionUserId]
                )
                currentUserAvatar = pickRowString(sessionUser, 'avatar', 'avatar_url') || null
                if (currentUserId && currentUserId !== userId) {
                    const blockedByRow = await db.get<{ c: number }>(
                        `SELECT 1 AS c FROM user_actions WHERE user_id = ? AND target_id = ? AND action_type = 'block' LIMIT 1`,
                        [userId, currentUserId]
                    )
                    initialIsBlockedByTarget = Boolean(blockedByRow?.c)
                }
            }
        }
    } catch (error) {
        console.error('Failed to get current user ID or block status:', error)
    }

    if (initialIsBlockedByTarget && currentUserId !== userId) {
        return { kind: 'blocked' }
    }

    const user = await db.get<DbUserRow>(
        `SELECT u.user_id AS id, u.display_name AS displayName, u.avatar_url AS avatar, u.banner_url AS banner,
                (SELECT COUNT(1) FROM user_actions f WHERE f.target_id = u.user_id AND f.action_type = 'follow') AS followersCount,
                u.is_verified AS isVerified
         FROM users u WHERE u.user_id = ?`,
        [userId]
    )

    if (!user) {
        return { kind: 'not_found' }
    }

    const live = await db.get<DbLiveRow>(
        `SELECT 
            room_id AS roomId,
            room_id AS userId,
            stream_status AS streamStatus,
            title,
            0 AS viewers,
            started_at AS startedAt,
            thumbnail_url AS thumbnail,
            stream_token AS src
         FROM room_streams
         WHERE room_id = ? AND stream_status IN ('ready', 'initializing', 'connected', 'streaming', 'live', 'live-inprogress', 'reconnected')
         ORDER BY COALESCE(started_at, created_at) DESC
         LIMIT 1`,
        [userId]
    )

    const [avatarFrame, groups] = await Promise.all([
        fetchUserActiveAvatarFrame(db, userId),
        fetchUserGroups(db, userId),
    ])

    const vodRows = await db.all<DbLiveStreamVodRow>(
        `SELECT 
            room_id AS roomId,
            room_id AS userId,
            title,
            thumbnail_url AS thumbnail,
            0 AS viewers,
            started_at AS startedAt,
            updated_at AS uploadedAt,
            category,
            created_at AS createdAt
         FROM room_streams
         WHERE room_id = ? AND stream_status NOT IN ('ready', 'initializing', 'connected', 'streaming', 'live', 'live-inprogress', 'reconnected')
         ORDER BY COALESCE(updated_at, created_at) DESC`,
        [userId]
    )

    const boardPostRows = await db.all<DbBoardPostRow>(
        `SELECT 
            bp.post_id AS id,
            bp.user_id AS userId,
            bp.created_at AS created_at_sec,
            bp.is_pinned AS pinned,
            bp.content,
            (SELECT COUNT(1) FROM user_board_post_comments c WHERE c.post_id = bp.post_id) AS comments,
            0 AS views,
            bp.thumbnail_url AS thumb,
            0 AS thumbCount,
            u.display_name AS displayName, u.avatar_url AS avatar
         FROM user_board_posts bp
         INNER JOIN users u ON bp.user_id = u.user_id
         WHERE bp.user_id = ?
         ORDER BY bp.is_pinned DESC, bp.created_at DESC`,
        [userId]
    )

    const vipLevel: 'none' | 'vip' | 'vvip' | 'svip' | 'royal' = 'none'

    const userRow = user as Record<string, unknown>
    const profile = {
        id: pickRowString(userRow, 'id', 'user_id') || userId,
        profileUrlPath: resolved.publicUserId,
        displayName: readDisplayName(userRow) || userId,
        avatar: pickRowString(userRow, 'avatar', 'avatar_url'),
        banner: pickRowString(userRow, 'banner', 'banner_url'),
        description: '',
        followersCount: pickRowNumber(userRow, 'followersCount', 'followerscount'),
        totalViewsCount: 0,
        isVerified: Boolean(user.isVerified === 1),
        vipLevel,
        avatarFrame,
        live: live
            ? {
                isLive: isStreamLiveByLifecycleStatus(live.streamStatus),
                roomId: live.roomId ?? '',
                title: live.title ?? '',
                viewers: Number(live.viewers ?? 0),
                startedAt: String(live.startedAt ?? '').trim(),
                thumbnail: live.thumbnail ?? '',
                src: live.src ?? undefined,
            }
            : undefined,
    }

    const vodList = (vodRows ?? []).map((v) => {
        const raw = v.uploadedAt ?? v.startedAt ?? v.createdAt
        let startedTs = 0
        if (raw != null && raw !== '') {
            if (typeof raw === 'number') {
                startedTs = raw < 1e12 ? Math.floor(raw * 1000) : Math.floor(raw)
            } else {
                const s = String(raw).trim()
                if (/^\d+$/.test(s)) {
                    const n = Number(s)
                    startedTs = n < 1e12 ? Math.floor(n * 1000) : Math.floor(n)
                } else {
                    const p = Date.parse(s)
                    startedTs = Number.isFinite(p) ? p : 0
                }
            }
        }
        const startedAtStr =
            startedTs > 0
                ? new Date(startedTs).toISOString()
                : v.startedAt != null
                  ? String(v.startedAt)
                  : v.uploadedAt != null
                    ? String(v.uploadedAt)
                    : ''
        const streamCategory = parseRoomStreamCategory(v.category)
        return {
            id: v.roomId,
            title: v.title,
            thumb: v.thumbnail ?? '',
            views: Number(v.viewers ?? 0),
            startedAt: startedAtStr,
            startedTs,
            duration: '',
            category: streamCategory ? `${streamCategory.groupId}:${streamCategory.itemId}` : '',
            tags: roomStreamCategoryToTagIds(v.category),
        }
    })

    const boardPosts = (boardPostRows ?? []).map((p) => {
        const postRow = p as Record<string, unknown>
        return {
        id: pickRowString(postRow, 'id', 'post_id') || String(p.id ?? ''),
        authorName: readDisplayName(postRow) || profile.displayName,
        authorAvatar: pickRowString(postRow, 'avatar', 'avatar_url') || profile.avatar,
        date:
            p.created_at_sec > 0
                ? new Date(p.created_at_sec * 1000).toISOString().slice(0, 10)
                : '',
        pinned: Boolean(p.pinned),
        content: p.content,
        comments: Number(p.comments ?? 0),
        views: Number(p.views ?? 0),
        thumb: p.thumb ?? '',
        thumbCount: pickRowNumber(postRow, 'thumbCount', 'thumbcount'),
        }
    })

    let initialIsFollowing = false
    let initialIsBlocked = false
    if (currentUserId && currentUserId !== userId) {
        const followExists = await db.get<{ c: number }>(
            `SELECT 1 AS c FROM user_actions WHERE user_id = ? AND target_id = ? AND action_type = 'follow' LIMIT 1`,
            [currentUserId, userId]
        )
        initialIsFollowing = Boolean(followExists?.c)
        const blockExists = await db.get<{ c: number }>(
            `SELECT 1 AS c FROM user_actions WHERE user_id = ? AND target_id = ? AND action_type = 'block' LIMIT 1`,
            [currentUserId, userId]
        )
        initialIsBlocked = Boolean(blockExists?.c)
    }

    if (postId) {
        const postRow = boardPostRows?.find((r) => r.id === postId)
        if (!postRow) {
            return { kind: 'post_not_found' }
        }
        const selectedPost: UserBoardPostItem =
            boardPosts.find((p) => p.id === postId) ?? {
                id: postRow.id,
                authorName: postRow.displayName ?? profile.displayName,
                authorAvatar: postRow.avatar ?? profile.avatar,
                date:
                    postRow.created_at_sec > 0
                        ? new Date(postRow.created_at_sec * 1000).toISOString().slice(0, 10)
                        : '',
                pinned: Boolean(postRow.pinned),
                content: postRow.content,
                comments: Number(postRow.comments ?? 0),
                views: Number(postRow.views ?? 0),
                thumb: postRow.thumb ?? '',
                thumbCount: Number(postRow.thumbCount ?? 0),
            }
        return {
            kind: 'ok',
            currentUserId,
            currentUserAvatar,
            selectedPostId: postId,
            selectedPost,
            data: {
                profile,
                vodList,
                boardPosts,
                initialIsFollowing,
                initialIsBlocked,
                initialIsBlockedByTarget,
                groups,
            },
        }
    }

    return {
        kind: 'ok',
        currentUserId,
        currentUserAvatar,
        data: {
            profile,
            vodList,
            boardPosts,
            initialIsFollowing,
            initialIsBlocked,
            initialIsBlockedByTarget,
            groups,
        },
    }
}

export async function loadUserPageData(
    userKey: string,
    opts?: { canonicalPathSuffix?: string; postId?: string }
): Promise<LoadUserPageResult> {
    const result = await fetchUserPageData(userKey, opts)
    if (result.kind === 'not_found') {
        redirect('/')
    }
    if (result.kind === 'post_not_found') {
        notFound()
    }
    if (result.kind === 'redirect') {
        redirect(result.redirectTo)
    }
    return result
}
