import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { sanitizeString, isValidId, isValidLength, isValidMessageType } from '@/lib/validation';
import { checkRateLimit, getRateLimitIdentifier, rateLimitError, RATE_LIMITS } from '@/lib/rate-limit';

/**
 * GET /api/messages?userId=xxx
 * Get conversations for a user, sorted by most recent message.
 * Each conversation includes the other user's info, last message, and unread count.
 */
export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const userId = searchParams.get('userId');

    if (!userId) {
      return NextResponse.json(
        { error: 'userId is required' },
        { status: 400 }
      );
    }

    if (!isValidId(userId)) {
      return NextResponse.json(
        { error: 'Invalid user ID format' },
        { status: 400 }
      );
    }

    // Verify the user exists
    const user = await db.user.findUnique({
      where: { id: userId },
      select: { id: true },
    });

    if (!user) {
      return NextResponse.json(
        { error: 'User not found' },
        { status: 404 }
      );
    }

    // Fetch all messages involving this user, with sender/receiver info,
    // ordered by most recent first so we can pick the latest per conversation
    const messages = await db.message.findMany({
      where: {
        OR: [
          { senderId: userId },
          { receiverId: userId },
        ],
      },
      include: {
        sender: {
          select: { id: true, name: true, phone: true, avatar: true },
        },
        receiver: {
          select: { id: true, name: true, phone: true, avatar: true },
        },
      },
      orderBy: { createdAt: 'desc' },
    });

    // Build conversation map: otherUserId -> conversation data
    // Since messages are ordered by createdAt desc, the first message
    // we encounter for each partner is the most recent one
    const conversationMap = new Map<
      string,
      {
        id: string;
        name: string;
        phone: string | null;
        avatar: string | null;
        lastMessage: string;
        lastMessageTime: Date;
        unreadCount: number;
      }
    >();

    for (const msg of messages) {
      const isSender = msg.senderId === userId;
      const otherUserId = isSender ? msg.receiverId : msg.senderId;
      const otherUser = isSender ? msg.receiver : msg.sender;

      if (!conversationMap.has(otherUserId)) {
        conversationMap.set(otherUserId, {
          id: otherUser.id,
          name: otherUser.name,
          phone: otherUser.phone,
          avatar: otherUser.avatar,
          lastMessage: msg.content,
          lastMessageTime: msg.createdAt,
          unreadCount: 0,
        });
      }
    }

    // Fetch unread counts grouped by sender (messages where current user is receiver)
    const unreadMessages = await db.message.findMany({
      where: {
        receiverId: userId,
        isRead: false,
      },
      select: { senderId: true },
    });

    const unreadCountMap = new Map<string, number>();
    for (const msg of unreadMessages) {
      const count = unreadCountMap.get(msg.senderId) || 0;
      unreadCountMap.set(msg.senderId, count + 1);
    }

    // Merge unread counts into conversations
    for (const [otherUserId, conv] of conversationMap) {
      conv.unreadCount = unreadCountMap.get(otherUserId) || 0;
    }

    // Convert to array (already sorted by most recent message due to query ordering)
    const conversations = Array.from(conversationMap.values());

    return NextResponse.json({ conversations });
  } catch (error) {
    console.error('Messages GET error:', error);
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}

/**
 * POST /api/messages
 * Send a new message.
 * Body: { senderId, receiverId, content, messageType? }
 */
export async function POST(request: NextRequest) {
  try {
    // Rate limit message sending
    const identifier = `messages:${getRateLimitIdentifier(request)}`;
    const rateLimit = checkRateLimit(identifier, RATE_LIMITS.api);
    if (!rateLimit.allowed) return rateLimitError(rateLimit.resetTime);

    const body = await request.json();
    const { senderId, receiverId, content, messageType } = body;

    // Validate required fields
    if (!senderId || !receiverId || !content) {
      return NextResponse.json(
        { error: 'Missing required fields: senderId, receiverId, content' },
        { status: 400 }
      );
    }

    if (!isValidId(senderId) || !isValidId(receiverId)) {
      return NextResponse.json(
        { error: 'Invalid sender or receiver ID format' },
        { status: 400 }
      );
    }

    if (senderId === receiverId) {
      return NextResponse.json(
        { error: 'Cannot send a message to yourself' },
        { status: 400 }
      );
    }

    if (!isValidLength(content, 1, 5000)) {
      return NextResponse.json(
        { error: 'Message content must be between 1 and 5000 characters' },
        { status: 400 }
      );
    }

    // Validate message type
    const msgType = messageType || 'text';
    if (!isValidMessageType(msgType)) {
      return NextResponse.json(
        { error: 'Invalid message type. Allowed: text, image, file' },
        { status: 400 }
      );
    }

    // Verify both users exist
    const [sender, receiver] = await Promise.all([
      db.user.findUnique({ where: { id: senderId }, select: { id: true } }),
      db.user.findUnique({ where: { id: receiverId }, select: { id: true } }),
    ]);

    if (!sender) {
      return NextResponse.json(
        { error: 'Sender not found' },
        { status: 404 }
      );
    }

    if (!receiver) {
      return NextResponse.json(
        { error: 'Receiver not found' },
        { status: 404 }
      );
    }

    // Create the message
    const message = await db.message.create({
      data: {
        senderId,
        receiverId,
        content: sanitizeString(content),
        messageType: msgType,
      },
      include: {
        sender: {
          select: { id: true, name: true, phone: true, avatar: true },
        },
        receiver: {
          select: { id: true, name: true, phone: true, avatar: true },
        },
      },
    });

    return NextResponse.json({ message }, { status: 201 });
  } catch (error) {
    console.error('Messages POST error:', error);
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}
