import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  Prisma,
  RobotLifecycleEventType,
  RobotEventRelatedType,
  ServiceTicketActivityType,
  ServiceTicketStatus,
  TicketSeverity,
} from '@prisma/client';
import { SkipAssertAccess } from '@common/decorators/skip-assert-access.decorator';

export interface CreateTicketInput {
  ticketNo: string;
  robotUnitId: string;
  customerId?: string;
  issueTypeCode: string;
  severity?: TicketSeverity;
  serviceRecord?: string;
}

@Injectable()
export class ServiceTicketService {
  private readonly logger = new Logger(ServiceTicketService.name);

  constructor(private readonly prisma: PrismaService) {}

  async create(input: CreateTicketInput, userId: string, organizationId: string) {
    return this.prisma.$transaction(async (tx) => {
      const ticket = await tx.serviceTicket.create({
        data: {
          ticketNo: input.ticketNo,
          robotUnitId: input.robotUnitId,
          customerId: input.customerId,
          issueTypeCode: input.issueTypeCode,
          severity: input.severity ?? TicketSeverity.P2,
          status: ServiceTicketStatus.NEW,
          serviceRecord: input.serviceRecord,
          openedAt: new Date(),
          openedById: userId,
          organizationId,
          createdById: userId,
        },
      });
      await tx.robotLifecycleEvent.create({
        data: {
          robotUnitId: input.robotUnitId,
          eventType: RobotLifecycleEventType.service_opened,
          actorUserId: userId,
          relatedType: RobotEventRelatedType.SERVICE_TICKET,
          relatedId: ticket.id,
          payload: { ticketNo: input.ticketNo, severity: ticket.severity } as Prisma.InputJsonValue,
          occurredAt: ticket.openedAt,
          organizationId,
          createdById: userId,
        },
      });
      return ticket;
    });
  }

  async findAll(q: {
    status?: ServiceTicketStatus;
    severity?: TicketSeverity;
    robotUnitId?: string;
    page?: number;
    limit?: number;
  }) {
    const { page = 1, limit = 20 } = q;
    const where: Prisma.ServiceTicketWhereInput = { deletedAt: null };
    if (q.status) where.status = q.status;
    if (q.severity) where.severity = q.severity;
    if (q.robotUnitId) where.robotUnitId = q.robotUnitId;
    const [items, total] = await Promise.all([
      this.prisma.serviceTicket.findMany({
        where,
        skip: (page - 1) * limit,
        take: limit,
        orderBy: { openedAt: 'desc' },
      }),
      this.prisma.serviceTicket.count({ where }),
    ]);
    return { items, total, page, limit, totalPages: Math.ceil(total / limit) };
  }

  async findOne(id: string) {
    const t = await this.prisma.serviceTicket.findFirst({
      where: { id, deletedAt: null },
      include: { activities: { orderBy: { occurredAt: 'desc' } } },
    });
    if (!t) throw new NotFoundException(`ServiceTicket ${id} 不存在`);
    return t;
  }

  @SkipAssertAccess('上方 findFirst({ id }) 已抓到对象')
  async update(id: string, input: { status?: ServiceTicketStatus; serviceRecord?: string; customerFeedback?: string; severity?: TicketSeverity }, userId: string) {
    const existing = await this.prisma.serviceTicket.findFirst({ where: { id, deletedAt: null } });
    if (!existing) throw new NotFoundException(`ServiceTicket ${id} 不存在`);
    await this.prisma.serviceTicket.update({
      where: { id },
      data: input,
    });
    if (input.status === ServiceTicketStatus.CLOSED && existing.status !== ServiceTicketStatus.CLOSED) {
      await this.closeTicket(id, userId);
    }
    return this.findOne(id);
  }

  private async closeTicket(id: string, userId: string) {
    const t = await this.prisma.serviceTicket.findUnique({ where: { id } });
    if (!t) return;
    await this.prisma.$transaction(async (tx) => {
      await tx.serviceTicket.update({
        where: { id },
        data: { closedAt: new Date(), resolvedById: userId },
      });
      await tx.robotLifecycleEvent.create({
        data: {
          robotUnitId: t.robotUnitId,
          eventType: RobotLifecycleEventType.service_closed,
          actorUserId: userId,
          relatedType: RobotEventRelatedType.SERVICE_TICKET,
          relatedId: id,
          payload: { ticketNo: t.ticketNo } as Prisma.InputJsonValue,
          occurredAt: new Date(),
          organizationId: t.organizationId,
          createdById: userId,
        },
      });
    });
  }

  async addActivity(
    ticketId: string,
    activityType: ServiceTicketActivityType,
    payload: any,
    userId: string,
  ) {
    const t = await this.prisma.serviceTicket.findFirst({ where: { id: ticketId, deletedAt: null } });
    if (!t) throw new NotFoundException(`ServiceTicket ${ticketId} 不存在`);
    return this.prisma.serviceTicketActivity.create({
      data: {
        ticketId,
        activityType,
        payload: (payload ?? {}) as Prisma.InputJsonValue,
        createdById: userId,
        occurredAt: new Date(),
      },
    });
  }
}
