import { ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
import { TicketStatus, UserRole } from '@prisma/client';
import { PrismaService } from '../database/prisma.service';
import { UpsertSupportTicketDto } from './dto/upsert-support-ticket.dto';

type RequestUser = {
  sub: string;
  role: UserRole;
};

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

  list(user: RequestUser) {
    return this.prisma.supportTicket.findMany({
      where: this.buildWhere(user),
      include: {
        user: {
          select: {
            email: true,
            phone: true,
            role: true,
          },
        },
      },
      orderBy: [{ updatedAt: 'desc' }, { createdAt: 'desc' }],
      take: 200,
    });
  }

  create(user: RequestUser, body: UpsertSupportTicketDto) {
    return this.prisma.supportTicket.create({
      data: {
        userId: user.sub,
        subject: body.subject,
        description: body.description,
        status: body.status ? (body.status as TicketStatus) : TicketStatus.OPEN,
        attachments: body.attachments ?? [],
      },
      include: { user: { select: { email: true, phone: true, role: true } } },
    });
  }

  async update(user: RequestUser, id: string, body: Partial<UpsertSupportTicketDto>) {
    await this.findOwned(user, id);
    return this.prisma.supportTicket.update({
      where: { id },
      data: {
        subject: body.subject,
        description: body.description,
        status: body.status ? (body.status as TicketStatus) : undefined,
        attachments: body.attachments ?? undefined,
      },
      include: { user: { select: { email: true, phone: true, role: true } } },
    });
  }

  async addAttachment(user: RequestUser, id: string, attachmentUrl: string) {
    const ticket = await this.findOwned(user, id);
    const current = Array.isArray(ticket.attachments) ? ticket.attachments.map(String) : [];
    return this.prisma.supportTicket.update({
      where: { id },
      data: {
        attachments: [...current, attachmentUrl],
      },
      include: { user: { select: { email: true, phone: true, role: true } } },
    });
  }

  async archive(user: RequestUser, id: string) {
    await this.findOwned(user, id);
    await this.prisma.supportTicket.delete({ where: { id } });
    return { ok: true, id };
  }

  private buildWhere(user: RequestUser) {
    if (user.role === UserRole.ADMIN || user.role === UserRole.SUPER_ADMIN) {
      return undefined;
    }
    return { userId: user.sub };
  }

  private async findOwned(user: RequestUser, id: string) {
    const ticket = await this.prisma.supportTicket.findUnique({ where: { id } });
    if (!ticket) {
      throw new NotFoundException('Chamado nao encontrado.');
    }
    if ((user.role === UserRole.ADMIN || user.role === UserRole.SUPER_ADMIN) || ticket.userId === user.sub) {
      return ticket;
    }
    throw new ForbiddenException('Este chamado nao pertence a sessao atual.');
  }
}
