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

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

  private async requireAdmin(wsId: string, userId: string) {
    const member = await this.prisma.workspaceMember.findUnique({
      where: { workspaceId_userId: { workspaceId: wsId, userId } },
    });
    if (!member || (member.role !== 'admin' && member.role !== 'owner')) {
      throw new ForbiddenException('Admin access required');
    }
    return member;
  }

  /**
   * Exporta los datos del workspace en formato JSON estructurado.
   * Incluye: canales, mensajes (no eliminados), miembros, archivos.
   */
  async exportWorkspace(wsId: string, userId: string) {
    await this.requireAdmin(wsId, userId);

    const [workspace, members, channels, files] = await Promise.all([
      this.prisma.workspace.findUnique({
        where: { id: wsId },
        select: {
          id: true,
          name: true,
          domain: true,
          createdAt: true,
        },
      }),
      this.prisma.workspaceMember.findMany({
        where: { workspaceId: wsId, deactivatedAt: null },
        include: {
          user: {
            select: {
              id: true,
              email: true,
              displayName: true,
              realName: true,
              title: true,
              createdAt: true,
            },
          },
        },
      }),
      this.prisma.channel.findMany({
        where: { workspaceId: wsId, isArchived: false },
        include: {
          _count: { select: { messages: true, members: true } },
        },
      }),
      this.prisma.file.aggregate({
        where: { workspaceId: wsId, isDeleted: false },
        _count: true,
        _sum: { sizeBytes: true },
      }),
    ]);

    // Export messages per channel (limit to non-deleted)
    const channelsExport = await Promise.all(
      channels.map(async ch => {
        const messages = await this.prisma.message.findMany({
          where: {
            channelId: ch.id,
            isDeleted: false,
          },
          orderBy: { ts: 'asc' },
          take: 1000, // Limit per channel for safety
          select: {
            id: true,
            text: true,
            userId: true,
            ts: true,
            isEdited: true,
            createdAt: true,
          },
        });

        return {
          id: ch.id,
          name: ch.name,
          type: ch.type,
          topic: ch.topic,
          purpose: ch.purpose,
          member_count: ch._count.members,
          message_count: ch._count.messages,
          messages: messages.map(m => ({
            id: m.id,
            text: m.text,
            user_id: m.userId,
            timestamp: m.ts,
            is_edited: m.isEdited,
            created_at: m.createdAt,
          })),
        };
      }),
    );

    return {
      export_date: new Date().toISOString(),
      workspace: workspace,
      members: members.map(m => ({
        id: m.id,
        user: {
          id: m.user.id,
          email: m.user.email,
          display_name: m.user.displayName,
          real_name: m.user.realName,
          title: m.user.title,
          created_at: m.user.createdAt,
        },
        role: m.role,
        joined_at: m.joinedAt,
      })),
      channels: channelsExport,
      files_summary: {
        count: files._count,
        total_bytes: files._sum.sizeBytes?.toString() ?? '0',
      },
    };
  }

  /**
   * Exporta los datos de un usuario específico (GDPR data portability).
   */
  async exportUser(userId: string, wsId: string) {
    const member = await this.prisma.workspaceMember.findUnique({
      where: { workspaceId_userId: { workspaceId: wsId, userId } },
      include: {
        user: {
          select: {
            id: true,
            email: true,
            displayName: true,
            realName: true,
            title: true,
            avatarUrl: true,
            timezone: true,
            createdAt: true,
          },
        },
      },
    });

    if (!member) return { error: 'User not found in this workspace' };

    const [messages, files, savedMessages, dms] = await Promise.all([
      this.prisma.message.findMany({
        where: { userId, workspaceId: wsId, isDeleted: false },
        orderBy: { ts: 'desc' },
        take: 5000,
        select: {
          id: true,
          text: true,
          channelId: true,
          ts: true,
          createdAt: true,
        },
      }),
      this.prisma.file.findMany({
        where: { uploaderId: userId, isDeleted: false },
        select: {
          id: true,
          filename: true,
          fileType: true,
          sizeBytes: true,
          createdAt: true,
        },
      }),
      this.prisma.savedMessage.findMany({
        where: { userId },
        include: {
          message: { select: { id: true, text: true, channelId: true } },
        },
      }),
      this.prisma.channel.findMany({
        where: {
          workspaceId: wsId,
          type: 'dm',
          members: { some: { userId } },
        },
        select: { id: true, name: true },
      }),
    ]);

    return {
      export_date: new Date().toISOString(),
      user: member.user,
      workspace_member: {
        role: member.role,
        guest_type: member.guestType,
        display_name: member.displayName,
        title: member.title,
        joined_at: member.joinedAt,
      },
      messages: messages.map(m => ({
        id: m.id,
        text: m.text,
        channel_id: m.channelId,
        timestamp: m.ts,
        created_at: m.createdAt,
      })),
      files: files.map(f => ({
        id: f.id,
        filename: f.filename,
        file_type: f.fileType,
        size_bytes: f.sizeBytes.toString(),
        created_at: f.createdAt,
      })),
      saved_messages: savedMessages.map(s => ({
        id: s.id,
        message: s.message,
        saved_at: s.savedAt,
      })),
      direct_messages: dms,
    };
  }
}