import { NextRequest, NextResponse } from 'next/server'
import { getDb } from '@/server/db'
import { validateSession } from '@/app/api/_helpers/session'

function formatRelativeTime(createdAt: string): { value: number; unit: 'just' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year' } {
    const now = new Date()
    const created = new Date(createdAt)
    const diffMs = now.getTime() - created.getTime()
    const diffSeconds = Math.floor(diffMs / 1000)
    const diffMinutes = Math.floor(diffSeconds / 60)
    const diffHours = Math.floor(diffMinutes / 60)
    const diffDays = Math.floor(diffHours / 24)
    const diffWeeks = Math.floor(diffDays / 7)
    const diffMonths = Math.floor(diffDays / 30)
    const diffYears = Math.floor(diffDays / 365)

    if (diffSeconds < 60) return { value: 0, unit: 'just' }
    if (diffMinutes < 60) return { value: diffMinutes, unit: 'minute' }
    if (diffHours < 24) return { value: diffHours, unit: 'hour' }
    if (diffDays < 7) return { value: diffDays, unit: 'day' }
    if (diffWeeks < 4) return { value: diffWeeks, unit: 'week' }
    if (diffMonths < 12) return { value: diffMonths, unit: 'month' }
    return { value: diffYears, unit: 'year' }
}

function buildNestedComments(
    flatComments: Array<{
        id: string
        userId: string
        author: string
        avatar: string | null
        content: string
        likes: number
        parentId: string | null
        replyTo: string | null
        createdAt: string
        editedAt: string | null
    }>
) {
    const commentMap = new Map<string, any>()
    const rootComments: any[] = []

    flatComments.forEach((comment) => {
        const commentObj = {
            id: comment.id,
            userId: comment.userId,
            author: comment.author,
            avatar: comment.avatar || '',
            content: comment.content,
            time: formatRelativeTime(comment.createdAt),
            likes: comment.likes,
            isPinned: false,
            pinnedBy: null as string | null,
            isLiked: false,
            replyTo: comment.replyTo || undefined,
            nestedReplies: [] as any[],
            isEdited: Boolean(comment.editedAt),
        }
        commentMap.set(comment.id, commentObj)
    })

    function getCommentDepth(commentId: string, visited: Set<string> = new Set()): number {
        if (visited.has(commentId)) return 0
        visited.add(commentId)
        const comment = flatComments.find((c) => c.id === commentId)
        if (!comment || !comment.parentId) return 0
        return getCommentDepth(comment.parentId, visited) + 1
    }

    function findParentAtDepth(commentId: string, targetDepth: number): string | null {
        const comment = flatComments.find((c) => c.id === commentId)
        if (!comment) return null
        const depth = getCommentDepth(commentId)
        if (depth === targetDepth) return commentId
        if (!comment.parentId) return null
        return findParentAtDepth(comment.parentId, targetDepth)
    }

    flatComments.forEach((comment) => {
        const commentObj = commentMap.get(comment.id)!
        if (comment.parentId) {
            const depth = getCommentDepth(comment.id)
            if (depth >= 3) {
                const thirdLevelParentId = findParentAtDepth(comment.id, 2)
                if (thirdLevelParentId) {
                    const thirdLevelParent = commentMap.get(thirdLevelParentId)
                    if (thirdLevelParent) {
                        const originalParent = commentMap.get(comment.parentId)
                        if (originalParent) commentObj.replyTo = originalParent.author
                        thirdLevelParent.nestedReplies.push(commentObj)
                    }
                } else {
                    rootComments.push(commentObj)
                }
            } else {
                const parent = commentMap.get(comment.parentId)
                if (parent) parent.nestedReplies.push(commentObj)
            }
        } else {
            rootComments.push(commentObj)
        }
    })

    function processComment(comment: any) {
        if (comment.nestedReplies?.length > 0) {
            comment.replies = comment.nestedReplies.length
            comment.nestedReplies.forEach(processComment)
            comment.nestedReplies.sort((a: any, b: any) => {
                const aComment = flatComments.find((c) => c.id === a.id)
                const bComment = flatComments.find((c) => c.id === b.id)
                const aTime = aComment?.createdAt || ''
                const bTime = bComment?.createdAt || ''
                return new Date(bTime).getTime() - new Date(aTime).getTime()
            })
        }
    }
    rootComments.forEach(processComment)

    rootComments.sort((a, b) => {
        const aTime = flatComments.find((c) => c.id === a.id)?.createdAt || ''
        const bTime = flatComments.find((c) => c.id === b.id)?.createdAt || ''
        return new Date(bTime).getTime() - new Date(aTime).getTime()
    })

    return rootComments
}

export async function GET(
    _request: NextRequest,
    { params }: { params: { postId: string } }
) {
    try {
        const postId = String(params?.postId ?? '')
        const db = await getDb()

        const post = await db.get<{ post_id: string }>(
            `SELECT post_id FROM user_board_posts WHERE post_id = ?`,
            [postId]
        )
        if (!post) {
            return NextResponse.json({ ok: false, error: 'POST_NOT_FOUND' }, { status: 404 })
        }

        const rows = await db.all<{
            id: string
            userId: string
            author: string
            avatar: string | null
            content: string
            parentId: string | null
            created_at_sec: number
            edited_at_sec: number | null
        }>(
            `SELECT
                c.comment_id AS id,
                c.user_id AS userId,
                u.display_name AS author,
                u.avatar_url AS avatar,
                c.content,
                c.parent_id AS parentId,
                c.created_at AS created_at_sec,
                c.edited_at AS edited_at_sec
            FROM user_board_post_comments c
            LEFT JOIN users u ON c.user_id = u.user_id
            WHERE c.post_id = ?
            ORDER BY c.created_at ASC`,
            [postId]
        )

        const flat = (Array.isArray(rows) ? rows : []).map((r) => ({
            id: r.id,
            userId: r.userId,
            author: r.author,
            avatar: r.avatar,
            content: r.content,
            likes: 0,
            parentId: r.parentId,
            replyTo: null as string | null,
            createdAt: new Date(r.created_at_sec * 1000).toISOString(),
            editedAt:
                r.edited_at_sec != null && Number(r.edited_at_sec) > 0
                    ? new Date(Number(r.edited_at_sec) * 1000).toISOString()
                    : null,
        }))

        const nested = buildNestedComments(flat)

        return NextResponse.json({ ok: true, data: nested })
    } catch (error: any) {
        console.error('Failed to fetch board post comments:', error)
        return NextResponse.json(
            { ok: false, message: error?.message || 'Failed to fetch comments' },
            { status: 500 }
        )
    }
}

export async function POST(
    request: NextRequest,
    { params }: { params: { postId: string } }
) {
    try {
        const postId = String(params?.postId ?? '')
        const userId = await validateSession(request)

        if (!userId) {
            return NextResponse.json({ ok: false, error: 'UNAUTHORIZED' }, { status: 401 })
        }

        const body = await request.json()
        const { content, parentId, replyTo } = body

        if (!content || !String(content).trim()) {
            return NextResponse.json({ ok: false, error: 'MISSING_FIELDS' }, { status: 400 })
        }

        const db = await getDb()

        const post = await db.get<{ post_id: string }>(
            `SELECT post_id FROM user_board_posts WHERE post_id = ?`,
            [postId]
        )
        if (!post) {
            return NextResponse.json({ ok: false, error: 'POST_NOT_FOUND' }, { status: 404 })
        }

        const user = await db.get<{ displayName: string }>(
            `SELECT display_name AS displayName FROM users WHERE user_id = ?`,
            [userId]
        )
        if (!user) {
            return NextResponse.json({ ok: false, error: 'USER_NOT_FOUND' }, { status: 404 })
        }

        const commentId = `bp-comment-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`
        const nowSec = Math.floor(Date.now() / 1000)

        await db.run(
            `INSERT INTO user_board_post_comments (comment_id, post_id, user_id, content, parent_id, created_at, edited_at)
             VALUES (?, ?, ?, ?, ?, ?, NULL)`,
            [commentId, postId, userId, String(content).trim(), parentId || null, nowSec]
        )

        const newComment = await db.get<{
            id: string
            author: string
            avatar: string | null
            content: string
            parentId: string | null
            created_at_sec: number
        }>(
            `SELECT c.comment_id AS id, u.display_name AS author, u.avatar_url AS avatar, c.content, c.parent_id AS parentId, c.created_at AS created_at_sec
             FROM user_board_post_comments c
             LEFT JOIN users u ON c.user_id = u.user_id
             WHERE c.comment_id = ?`,
            [commentId]
        )

        if (!newComment) {
            return NextResponse.json({ ok: false, error: 'FAILED_TO_CREATE' }, { status: 500 })
        }

        const createdIso = new Date(newComment.created_at_sec * 1000).toISOString()

        return NextResponse.json({
            ok: true,
            data: {
                id: newComment.id,
                author: newComment.author,
                avatar: newComment.avatar || '',
                content: newComment.content,
                time: formatRelativeTime(createdIso),
                likes: 0,
                replyTo: replyTo || undefined,
            },
        })
    } catch (error: any) {
        console.error('Failed to create board post comment:', error)
        return NextResponse.json(
            { ok: false, message: error?.message || 'Failed to create comment' },
            { status: 500 }
        )
    }
}

export async function DELETE(
    request: NextRequest,
    { params }: { params: { postId: string } }
) {
    try {
        const postId = String(params?.postId ?? '')
        const userId = await validateSession(request)

        if (!userId) {
            return NextResponse.json({ ok: false, error: 'UNAUTHORIZED' }, { status: 401 })
        }

        const { searchParams } = new URL(request.url)
        const commentId = searchParams.get('commentId')

        if (!commentId) {
            return NextResponse.json({ ok: false, error: 'MISSING_COMMENT_ID' }, { status: 400 })
        }

        const db = await getDb()

        const comment = await db.get<{ userId: string; postId: string }>(
            `SELECT user_id AS userId, post_id AS postId FROM user_board_post_comments WHERE comment_id = ?`,
            [commentId]
        )

        if (!comment) {
            return NextResponse.json({ ok: false, error: 'COMMENT_NOT_FOUND' }, { status: 404 })
        }

        if (comment.postId !== postId) {
            return NextResponse.json({ ok: false, error: 'FORBIDDEN' }, { status: 403 })
        }

        const post = await db.get<{ userId: string }>(
            `SELECT user_id AS userId FROM user_board_posts WHERE post_id = ?`,
            [postId]
        )
        if (!post) {
            return NextResponse.json({ ok: false, error: 'POST_NOT_FOUND' }, { status: 404 })
        }

        const postOwnerId = String(post.userId).trim()
        const commentOwnerId = String(comment.userId).trim()
        const currentUserId = String(userId).trim()

        if (commentOwnerId !== currentUserId && postOwnerId !== currentUserId) {
            return NextResponse.json({ ok: false, error: 'FORBIDDEN' }, { status: 403 })
        }

        const childResult = await db.all<{ id: string }>(
            `WITH RECURSIVE child_comments AS (
                SELECT comment_id AS id FROM user_board_post_comments WHERE parent_id = ?
                UNION ALL
                SELECT c.comment_id AS id FROM user_board_post_comments c
                INNER JOIN child_comments ch ON c.parent_id = ch.id
            )
            SELECT id FROM child_comments`,
            [commentId]
        )
        const childComments = Array.isArray(childResult) ? childResult : []

        if (childComments.length > 0) {
            const ids = childComments.map((c) => c.id)
            const placeholders = ids.map(() => '?').join(',')
            await db.run(
                `DELETE FROM user_board_post_comments WHERE comment_id IN (${placeholders})`,
                ids
            )
        }

        await db.run(`DELETE FROM user_board_post_comments WHERE comment_id = ?`, [commentId])

        return NextResponse.json({ ok: true, message: 'Comment deleted' })
    } catch (error: any) {
        console.error('Failed to delete board post comment:', error)
        return NextResponse.json(
            { ok: false, message: error?.message || 'Failed to delete comment' },
            { status: 500 }
        )
    }
}
