import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';
import { PrismaService } from '@chatapp/database';

@Injectable()
export class BookmarksService {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Lista los bookmarks de un canal.
   */
  async listByChannel(channelId: string, wsId: string) {
    const bookmarks = await this.prisma.channelBookmark.findMany({
      where: { channelId },
      orderBy: { orderIndex: 'asc' },
      include: {
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
        channel: { select: { id: true, name: true, workspaceId: true } },
      },
    });

    // Verify the channel belongs to the workspace
    if (bookmarks.length > 0 && bookmarks[0].channel.workspaceId !== wsId) {
      throw new ForbiddenException('Channel does not belong to this workspace');
    }

    return {
      bookmarks: bookmarks.map(b => ({
        id: b.id,
        type: b.type,
        title: b.title,
        url: b.url,
        target_channel_id: b.targetChannelId,
        target_message_id: b.targetMessageId,
        emoji: b.emoji,
        order_index: b.orderIndex,
        created_by: b.createdByUser,
        created_at: b.createdAt,
      })),
    };
  }

  async create(
    channelId: string,
    wsId: string,
    userId: string,
    dto: { type: string; title?: string; url?: string; target_channel_id?: string; target_message_id?: string; emoji?: string },
  ) {
    const channel = await this.prisma.channel.findFirst({
      where: { id: channelId, workspaceId: wsId },
    });
    if (!channel) throw new NotFoundException('Channel not found');

    const maxOrder = await this.prisma.channelBookmark.aggregate({
      where: { channelId },
      _max: { orderIndex: true },
    });

    const bookmark = await this.prisma.channelBookmark.create({
      data: {
        channelId,
        type: dto.type,
        title: dto.title,
        url: dto.url,
        targetChannelId: dto.target_channel_id,
        targetMessageId: dto.target_message_id,
        emoji: dto.emoji,
        orderIndex: (maxOrder._max.orderIndex ?? -1) + 1,
        createdBy: userId,
      },
      include: {
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });

    return {
      id: bookmark.id,
      type: bookmark.type,
      title: bookmark.title,
      url: bookmark.url,
      target_channel_id: bookmark.targetChannelId,
      target_message_id: bookmark.targetMessageId,
      emoji: bookmark.emoji,
      order_index: bookmark.orderIndex,
      created_by: bookmark.createdByUser,
      created_at: bookmark.createdAt,
    };
  }

  async update(id: string, wsId: string, dto: any) {
    const bookmark = await this.prisma.channelBookmark.findFirst({
      where: { id },
      include: { channel: { select: { workspaceId: true } } },
    });
    if (!bookmark) throw new NotFoundException('Bookmark not found');
    if (bookmark.channel.workspaceId !== wsId) {
      throw new ForbiddenException('Bookmark does not belong to this workspace');
    }

    const data: any = {};
    if (dto.title !== undefined) data.title = dto.title;
    if (dto.url !== undefined) data.url = dto.url;
    if (dto.emoji !== undefined) data.emoji = dto.emoji;
    if (dto.order_index !== undefined) data.orderIndex = dto.order_index;

    return this.prisma.channelBookmark.update({ where: { id }, data });
  }

  async delete(id: string, wsId: string) {
    const bookmark = await this.prisma.channelBookmark.findFirst({
      where: { id },
      include: { channel: { select: { workspaceId: true } } },
    });
    if (!bookmark) throw new NotFoundException('Bookmark not found');
    if (bookmark.channel.workspaceId !== wsId) {
      throw new ForbiddenException('Bookmark does not belong to this workspace');
    }

    await this.prisma.channelBookmark.delete({ where: { id } });
    return { deleted: true };
  }

  async reorder(channelId: string, wsId: string, bookmarkIds: string[]) {
    const channel = await this.prisma.channel.findFirst({
      where: { id: channelId, workspaceId: wsId },
    });
    if (!channel) throw new NotFoundException('Channel not found');

    await Promise.all(
      bookmarkIds.map((id, index) =>
        this.prisma.channelBookmark.update({
          where: { id, channelId },
          data: { orderIndex: index },
        }),
      ),
    );

    return { reordered: true };
  }
}