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

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

  /**
   * Lista los mensajes programados del usuario en el workspace.
   */
  async list(userId: string, wsId: string, query: { status?: string } = {}) {
    const where: any = { userId, workspaceId: wsId };
    if (query.status) where.status = query.status;

    const messages = await this.prisma.scheduledMessage.findMany({
      where,
      orderBy: { scheduledFor: 'asc' },
      include: {
        channel: { select: { id: true, name: true, handle: true } },
      },
    });

    return {
      scheduled_messages: messages.map(m => ({
        id: m.id,
        channel: m.channel,
        text: m.text,
        blocks: m.blocks,
        scheduled_for: m.scheduledFor,
        status: m.status,
        sent_message_id: m.sentMessageId,
        created_at: m.createdAt,
      })),
    };
  }

  async create(userId: string, wsId: string, dto: { channel_id: string; text?: string; blocks?: any; scheduled_for: string }) {
    const channel = await this.prisma.channel.findFirst({
      where: { id: dto.channel_id, workspaceId: wsId },
    });
    if (!channel) throw new NotFoundException('Channel not found');

    const scheduledFor = new Date(dto.scheduled_for);
    if (scheduledFor <= new Date()) {
      throw new BadRequestException('Scheduled time must be in the future');
    }

    const scheduled = await this.prisma.scheduledMessage.create({
      data: {
        workspaceId: wsId,
        channelId: dto.channel_id,
        userId,
        text: dto.text,
        blocks: dto.blocks ?? undefined,
        scheduledFor,
        status: 'pending',
      },
      include: {
        channel: { select: { id: true, name: true, handle: true } },
      },
    });

    return {
      id: scheduled.id,
      channel: scheduled.channel,
      text: scheduled.text,
      blocks: scheduled.blocks,
      scheduled_for: scheduled.scheduledFor,
      status: scheduled.status,
      created_at: scheduled.createdAt,
    };
  }

  async update(id: string, userId: string, wsId: string, dto: { text?: string; blocks?: any; scheduled_for?: string }) {
    const scheduled = await this.prisma.scheduledMessage.findFirst({
      where: { id, userId, workspaceId: wsId, status: 'pending' },
    });
    if (!scheduled) throw new NotFoundException('Scheduled message not found or already sent');

    const data: any = {};
    if (dto.text !== undefined) data.text = dto.text;
    if (dto.blocks !== undefined) data.blocks = dto.blocks;
    if (dto.scheduled_for !== undefined) {
      const scheduledFor = new Date(dto.scheduled_for);
      if (scheduledFor <= new Date()) {
        throw new BadRequestException('Scheduled time must be in the future');
      }
      data.scheduledFor = scheduledFor;
    }

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

  async cancel(id: string, userId: string, wsId: string) {
    const scheduled = await this.prisma.scheduledMessage.findFirst({
      where: { id, userId, workspaceId: wsId, status: 'pending' },
    });
    if (!scheduled) throw new NotFoundException('Scheduled message not found or already sent');

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

    return { cancelled: true };
  }

  /**
   * Obtiene mensajes programados pendientes que ya deben enviarse.
   * Usado por un cron job del worker.
   */
  async getDueMessages(limit = 100) {
    return this.prisma.scheduledMessage.findMany({
      where: {
        status: 'pending',
        scheduledFor: { lte: new Date() },
      },
      take: limit,
      orderBy: { scheduledFor: 'asc' },
    });
  }

  /**
   * Marca un mensaje programado como enviado y lo vincula al mensaje creado.
   */
  async markAsSent(id: string, sentMessageId: string) {
    return this.prisma.scheduledMessage.update({
      where: { id },
      data: { status: 'sent', sentMessageId },
    });
  }
}