import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { PrismaService } from '../../prisma/prisma.service';
import { CreateOrderDto } from './dto/create-order.dto';
import { UpdateOrderDto } from './dto/update-order.dto';
import { CompleteOrderDto } from './dto/complete-order.dto';
import { QueryOrderDto } from './dto/query-order.dto';
import { OrderStatus } from '@prisma/client';

@Injectable()
export class OrdersService {
  constructor(
    private prisma: PrismaService,
    private events: EventEmitter2,
  ) {}

  async create(tenantId: string, userId: string, dto: CreateOrderDto) {
    const number = await this.nextOrderNumber(tenantId);
    return this.prisma.serviceOrder.create({
      data: { ...dto, tenantId, technicianId: userId, number },
      include: { client: true, technician: { select: { name: true } } },
    });
  }

  async findAll(tenantId: string, query: QueryOrderDto) {
    const { status, clientId, page = 1, limit = 20, search } = query;
    const skip = (page - 1) * limit;

    const where: any = { tenantId };
    if (status) where.status = status;
    if (clientId) where.clientId = clientId;
    if (search) {
      where.OR = [
        { description: { contains: search, mode: 'insensitive' } },
        { serviceType: { contains: search, mode: 'insensitive' } },
        { client: { name: { contains: search, mode: 'insensitive' } } },
      ];
    }

    const [data, total] = await Promise.all([
      this.prisma.serviceOrder.findMany({
        where,
        skip,
        take: limit,
        orderBy: { createdAt: 'desc' },
        include: {
          client: { select: { name: true, phone: true } },
          technician: { select: { name: true } },
          attachments: true,
          _count: { select: { attachments: true } },
        },
      }),
      this.prisma.serviceOrder.count({ where }),
    ]);

    return { data, total, page, limit, pages: Math.ceil(total / limit) };
  }

  async findOne(tenantId: string, id: string) {
    const order = await this.prisma.serviceOrder.findFirst({
      where: { id, tenantId },
      include: {
        client: true,
        technician: { select: { id: true, name: true, email: true } },
        attachments: true,
        reminders: true,
      },
    });
    if (!order) throw new NotFoundException('Ordem de serviço não encontrada');
    return order;
  }

  async update(tenantId: string, id: string, dto: UpdateOrderDto) {
    await this.findOne(tenantId, id);
    return this.prisma.serviceOrder.update({
      where: { id },
      data: dto,
      include: { client: true },
    });
  }

  async complete(tenantId: string, id: string, dto: CompleteOrderDto) {
    const order = await this.findOne(tenantId, id);
    if (order.status === OrderStatus.DONE) {
      throw new BadRequestException('Ordem já foi concluída');
    }

    const completed = await this.prisma.serviceOrder.update({
      where: { id },
      data: {
        status: OrderStatus.DONE,
        completedAt: new Date(),
        clientSignature: dto.clientSignature,
        notes: dto.notes,
        value: dto.value,
      },
    });

    if (dto.recurrenceMonths) {
      const nextDate = new Date();
      nextDate.setMonth(nextDate.getMonth() + dto.recurrenceMonths);

      await this.prisma.reminder.create({
        data: {
          tenantId,
          clientId: order.clientId,
          orderId: id,
          nextMaintenanceDate: nextDate,
          recurrenceMonths: dto.recurrenceMonths,
          status: 'PENDING',
        },
      });

      this.events.emit('reminder.created', { tenantId, clientId: order.clientId });
    }

    this.events.emit('order.completed', { tenantId, orderId: id });
    return completed;
  }

  async addAttachment(orderId: string, url: string, filename: string, mimetype: string, size: number) {
    return this.prisma.attachment.create({ data: { orderId, url, filename, mimetype, size } });
  }

  private async nextOrderNumber(tenantId: string): Promise<number> {
    const last = await this.prisma.serviceOrder.findFirst({
      where: { tenantId },
      orderBy: { number: 'desc' },
      select: { number: true },
    });
    return (last?.number ?? 0) + 1;
  }
}
