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

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

  /**
   * Lista los canales compartidos de un workspace (tanto enviados como recibidos).
   */
  async list(wsId: string) {
    const [outgoing, incoming] = await Promise.all([
      this.prisma.sharedChannel.findMany({
        where: { sourceWorkspaceId: wsId },
        include: {
          channel: { select: { id: true, name: true, handle: true, type: true } },
          createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
          acceptedByUser: { select: { id: true, displayName: true } },
        },
        orderBy: { createdAt: 'desc' },
      }),
      this.prisma.sharedChannel.findMany({
        where: { targetWorkspaceId: wsId },
        include: {
          channel: { select: { id: true, name: true, handle: true, type: true } },
          createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
          acceptedByUser: { select: { id: true, displayName: true } },
        },
        orderBy: { createdAt: 'desc' },
      }),
    ]);

    return {
      outgoing: outgoing.map(this.mapShared),
      incoming: incoming.map(this.mapShared),
    };
  }

  private mapShared(s: any) {
    return {
      id: s.id,
      channel: s.channel,
      source_workspace_id: s.sourceWorkspaceId,
      target_workspace_id: s.targetWorkspaceId,
      target_channel_name: s.targetChannelName,
      target_channel_topic: s.targetChannelTopic,
      target_is_private: s.targetIsPrivate,
      status: s.status,
      accepted_at: s.acceptedAt,
      accepted_by: s.acceptedByUser,
      created_by: s.createdByUser,
      created_at: s.createdAt,
    };
  }

  /**
   * Inicia un Slack Connect compartiendo un canal con otro workspace.
   */
  async share(wsId: string, userId: string, dto: { channel_id: string; target_workspace_id: string; target_channel_name?: string; target_channel_topic?: string; target_is_private?: boolean }) {
    const channel = await this.prisma.channel.findFirst({
      where: { id: dto.channel_id, workspaceId: wsId },
    });
    if (!channel) throw new NotFoundException('Channel not found');

    const targetWorkspace = await this.prisma.workspace.findUnique({
      where: { id: dto.target_workspace_id },
    });
    if (!targetWorkspace) throw new NotFoundException('Target workspace not found');
    if (targetWorkspace.id === wsId) throw new BadRequestException('Cannot share with the same workspace');

    const shared = await this.prisma.sharedChannel.create({
      data: {
        channelId: dto.channel_id,
        sourceWorkspaceId: wsId,
        targetWorkspaceId: dto.target_workspace_id,
        targetChannelName: dto.target_channel_name,
        targetChannelTopic: dto.target_channel_topic,
        targetIsPrivate: dto.target_is_private ?? false,
        status: 'pending',
        createdBy: userId,
      },
      include: {
        channel: { select: { id: true, name: true, handle: true, type: true } },
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });

    return this.mapShared(shared);
  }

  /**
   * Acepta un canal compartido entrante (desde el workspace destino).
   */
  async accept(id: string, wsId: string, userId: string) {
    const shared = await this.prisma.sharedChannel.findUnique({ where: { id } });
    if (!shared) throw new NotFoundException('Shared channel invitation not found');
    if (shared.targetWorkspaceId !== wsId) {
      throw new ForbiddenException('This invitation is not for your workspace');
    }
    if (shared.status !== 'pending') throw new BadRequestException('Invitation already processed');

    const updated = await this.prisma.sharedChannel.update({
      where: { id },
      data: {
        status: 'accepted',
        acceptedAt: new Date(),
        acceptedBy: userId,
      },
      include: {
        channel: { select: { id: true, name: true, handle: true, type: true } },
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
        acceptedByUser: { select: { id: true, displayName: true } },
      },
    });

    return this.mapShared(updated);
  }

  /**
   * Rechaza una invitación de canal compartido.
   */
  async decline(id: string, wsId: string) {
    const shared = await this.prisma.sharedChannel.findUnique({ where: { id } });
    if (!shared) throw new NotFoundException('Shared channel invitation not found');
    if (shared.targetWorkspaceId !== wsId) {
      throw new ForbiddenException('This invitation is not for your workspace');
    }
    if (shared.status !== 'pending') throw new BadRequestException('Invitation already processed');

    await this.prisma.sharedChannel.update({
      where: { id },
      data: { status: 'declined' },
    });

    return { declined: true };
  }

  /**
   * Desconecta un canal compartido que ya estaba aceptado.
   */
  async disconnect(id: string, wsId: string) {
    const shared = await this.prisma.sharedChannel.findUnique({ where: { id } });
    if (!shared) throw new NotFoundException('Shared channel not found');
    if (shared.sourceWorkspaceId !== wsId && shared.targetWorkspaceId !== wsId) {
      throw new ForbiddenException('Not authorized to disconnect this shared channel');
    }

    await this.prisma.sharedChannel.update({
      where: { id },
      data: { status: 'disconnected' },
    });

    return { disconnected: true };
  }

  async findById(id: string) {
    const shared = await this.prisma.sharedChannel.findUnique({
      where: { id },
      include: {
        channel: { select: { id: true, name: true, handle: true, type: true } },
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
        acceptedByUser: { select: { id: true, displayName: true } },
      },
    });

    if (!shared) throw new NotFoundException('Shared channel not found');
    return this.mapShared(shared);
  }
}