// ── Messages: Collection ─────────────────────────────────────────────────────
// GET   /api/conversations/[id]/messages  — List messages in a conversation
// POST  /api/conversations/[id]/messages  — Send a new message
// DELETE /api/conversations/[id]/messages — Delete own message (by messageId in body)
// PATCH  /api/conversations/[id]/messages — Edit own message content
//
// Auth: authenticated; user must be a participant in the conversation

import { NextRequest, NextResponse } from "next/server"
import { getSessionUser } from "@/lib/auth"
import { query } from "@/lib/db"
import { avatarSvgUrl } from "@/lib/avatar"
import { hasBlockedCodeExtension } from "@/lib/blocked-extensions"

// ── GET ──────────────────────────────────────────────────────────────────────

export async function GET(
  _request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  try {
    const user = await getSessionUser()
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

    const { id } = await params

    const { searchParams } = new URL(_request.url)
    const limit = parseInt(searchParams.get("limit") || "100", 10)
    const offset = parseInt(searchParams.get("offset") || "0", 10)
    const before = searchParams.get("before") || ""

    // Verify user is a participant
    const partCheck = await query(
      `SELECT 1 FROM conversation_participants WHERE conversation_id = $1 AND user_id = $2`,
      [id, user.id]
    )
    if (partCheck.rows.length === 0) {
      return NextResponse.json({ error: "Not a participant" }, { status: 403 })
    }

    let msgSql = `SELECT m.id, m.sender_id, m.content, m.created_at, m.updated_at, m.deleted_at,
                         u.first_name || ' ' || u.last_name AS sender_name,
                         u.email AS sender_email,
                         u.avatar_url AS sender_avatar_url
                  FROM messages m
                  JOIN users u ON u.id = m.sender_id
                  WHERE m.conversation_id = $1 AND m.deleted_at IS NULL`
    const msgParams: any[] = [id]

    // Optional cursor-based pagination: fetch messages before a given timestamp
    if (before) {
      msgSql += ` AND m.created_at < $2`
      msgParams.push(before)
    }

    msgSql += ` ORDER BY m.created_at ASC`
    msgSql += ` LIMIT $${msgParams.length + 1} OFFSET $${msgParams.length + 2}`
    msgParams.push(limit, offset)

    // Fetch messages and other participant's last_read_at in parallel
    const [msgResult, otherReadResult] = await Promise.all([
      query(msgSql, msgParams),
      query(
        `SELECT last_read_at FROM conversation_participants
         WHERE conversation_id = $1 AND user_id != $2`,
        [id, user.id],
      ),
    ])

    const otherLastReadAt = otherReadResult.rows[0]?.last_read_at
      ? new Date(otherReadResult.rows[0].last_read_at).getTime()
      : 0

    // Mark outgoing messages as "read" if the other participant has seen them
    const messages = msgResult.rows.map((row: any) => ({
      id: row.id,
      conversationId: id,
      senderId: row.sender_id,
      senderName: row.sender_name,
      senderAvatar: avatarSvgUrl(row.sender_name),
      content: row.content,
      timestamp: formatTime(new Date(row.created_at)),
      createdAt: row.created_at,
      read: row.sender_id === user.id
        ? new Date(row.created_at).getTime() <= otherLastReadAt
        : true,
    }))

    return NextResponse.json({ messages })
  } catch (error) {
    console.error("Messages error:", error)
    return NextResponse.json({ error: "Failed to load messages" }, { status: 500 })
  }
}

// ── POST ─────────────────────────────────────────────────────────────────────

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  try {
    const user = await getSessionUser()
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

    const { id } = await params

    // Verify user is a participant
    const partCheck = await query(
      `SELECT 1 FROM conversation_participants WHERE conversation_id = $1 AND user_id = $2`,
      [id, user.id]
    )
    if (partCheck.rows.length === 0) {
      return NextResponse.json({ error: "Not a participant" }, { status: 403 })
    }

    const { content } = await request.json()
    if (!content?.trim()) {
      return NextResponse.json({ error: "Message content is required" }, { status: 400 })
    }

    // Server-side check: reject messages with blocked code file extensions
    try {
      const parsed = JSON.parse(content)
      if (parsed.fileAttachments && Array.isArray(parsed.fileAttachments)) {
        for (const f of parsed.fileAttachments) {
          if (f.name && hasBlockedCodeExtension(f.name)) {
            return NextResponse.json({ error: `Blocked file type: ${f.name}` }, { status: 400 })
          }
        }
      }
    } catch {}

    const result = await query(
      `INSERT INTO messages (conversation_id, sender_id, content)
       VALUES ($1, $2, $3)
       RETURNING id, created_at`,
      [id, user.id, content.trim()],
    )

    // Bump the conversation's updated_at timestamp
    await query(
      `UPDATE conversations SET updated_at = NOW() WHERE id = $1`,
      [id],
    )

    const msg = result.rows[0]
    const senderName = `${user.firstName} ${user.lastName}`

    // Notify the other participant about the new message
    const otherResult = await query(
      `SELECT user_id FROM conversation_participants
       WHERE conversation_id = $1 AND user_id != $2`,
      [id, user.id],
    )

    for (const row of otherResult.rows) {
      await query(
        `INSERT INTO notifications (user_id, type, title, description, link, context_id, context_type)
         VALUES ($1, 'chat_message', 'New Message', $2, '/chats', $3, 'conversation')`,
        [row.user_id, `${senderName} sent a message`, id],
      )
    }

    return NextResponse.json({
      message: {
        id: msg.id,
        conversationId: id,
        senderId: user.id,
        senderName,
        senderAvatar: user.avatar,
        content: content.trim(),
        timestamp: formatTime(new Date(msg.created_at)),
        createdAt: msg.created_at,
        read: false,
      },
    })
  } catch (error) {
    console.error("Send message error:", error)
    return NextResponse.json({ error: "Failed to send message" }, { status: 500 })
  }
}

// ── Helpers ──────────────────────────────────────────────────────────────────

/**
 * Formats a Date to a short time string.
 * Shows time only for today, date + time for older messages.
 */
function formatTime(date: Date): string {
  const now = new Date()
  const isToday = date.toDateString() === now.toDateString()
  if (isToday) {
    return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
  }
  return date.toLocaleDateString([], { month: "short", day: "numeric" }) + " " +
    date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
}

// ── DELETE ───────────────────────────────────────────────────────────────────

export async function DELETE(
  _request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  try {
    const user = await getSessionUser()
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

    const { id } = await params
    const body = await _request.json()
    const messageId = body.messageId
    if (!messageId) return NextResponse.json({ error: "messageId required" }, { status: 400 })

    // Only the sender can soft-delete their own message
    const result = await query(
      `UPDATE messages SET deleted_at = NOW() WHERE id = $1 AND sender_id = $2 AND conversation_id = $3 RETURNING id`,
      [messageId, user.id, id],
    )
    if (result.rows.length === 0) {
      return NextResponse.json({ error: "Message not found or not yours" }, { status: 404 })
    }

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error("Delete message error:", error)
    return NextResponse.json({ error: "Failed to delete message" }, { status: 500 })
  }
}

// ── PATCH ────────────────────────────────────────────────────────────────────

export async function PATCH(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  try {
    const user = await getSessionUser()
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

    const { id } = await params
    const body = await request.json()
    const messageId = body.messageId
    const newContent = body.content
    if (!messageId || !newContent?.trim()) {
      return NextResponse.json({ error: "messageId and content required" }, { status: 400 })
    }

    // Only the sender can edit their own message; also check it's not deleted
    const result = await query(
      `UPDATE messages SET content = $1, updated_at = NOW() WHERE id = $2 AND sender_id = $3 AND conversation_id = $4 AND deleted_at IS NULL RETURNING id`,
      [newContent.trim(), messageId, user.id, id],
    )
    if (result.rows.length === 0) {
      return NextResponse.json({ error: "Message not found or not yours" }, { status: 404 })
    }

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error("Edit message error:", error)
    return NextResponse.json({ error: "Failed to edit message" }, { status: 500 })
  }
}
