import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  Prisma,
  QualityLabelStatus,
  RobotPhysicalStatus,
  StickerStatus,
  FccStatus,
  LogisticsStatus,
  RobotLifecycleEventType,
  RobotEventRelatedType,
} from '@prisma/client';

/**
 * 按 robot 维度的子记录集合服务
 *   - QualityLabelRecord (7 行/台 节点 09)
 *   - RobotPackageReadiness (1 行/台 节点 11)
 *   - InspectionRecord (0-N 节点 08)
 *   - LogisticsLeg (1-N 节点 04)
 *   - ComplianceCheck (1 行/台 节点 03/05/06)
 */
@Injectable()
export class RobotRecordsService {
  private readonly logger = new Logger(RobotRecordsService.name);

  constructor(private readonly prisma: PrismaService) {}

  // ---- QualityLabel ----

  async upsertQualityLabel(
    robotUnitId: string,
    labelTypeCode: string,
    data: { status?: QualityLabelStatus; appliedById?: string; verifiedById?: string; photoAttachmentId?: string },
    userId: string,
    organizationId: string,
  ) {
    return this.prisma.$transaction(async (tx) => {
      const result = await tx.qualityLabelRecord.upsert({
        where: { robotUnitId_labelTypeCode: { robotUnitId, labelTypeCode } },
        update: {
          status: data.status,
          appliedAt:
            data.status === QualityLabelStatus.APPLIED ||
            data.status === QualityLabelStatus.VERIFIED
              ? new Date()
              : undefined,
          verifiedAt: data.status === QualityLabelStatus.VERIFIED ? new Date() : undefined,
          appliedById: data.appliedById,
          verifiedById: data.verifiedById,
          photoAttachmentId: data.photoAttachmentId,
        },
        create: {
          robotUnitId,
          labelTypeCode,
          status: data.status ?? QualityLabelStatus.PENDING,
          appliedAt:
            data.status === QualityLabelStatus.APPLIED ||
            data.status === QualityLabelStatus.VERIFIED
              ? new Date()
              : null,
          verifiedAt: data.status === QualityLabelStatus.VERIFIED ? new Date() : null,
          appliedById: data.appliedById,
          verifiedById: data.verifiedById,
          photoAttachmentId: data.photoAttachmentId,
          organizationId,
          createdById: userId,
        },
      });
      if (data.status === QualityLabelStatus.APPLIED || data.status === QualityLabelStatus.VERIFIED) {
        await tx.robotLifecycleEvent.create({
          data: {
            robotUnitId,
            eventType: RobotLifecycleEventType.label_applied,
            actorUserId: userId,
            relatedType: RobotEventRelatedType.LABEL,
            relatedId: result.id,
            payload: { labelTypeCode, status: data.status } as Prisma.InputJsonValue,
            occurredAt: new Date(),
            organizationId,
            createdById: userId,
          },
        });
      }
      return result;
    });
  }

  listQualityLabels(robotUnitId: string) {
    return this.prisma.qualityLabelRecord.findMany({ where: { robotUnitId } });
  }

  // ---- PackageReadiness ----

  async upsertReadiness(
    robotUnitId: string,
    data: Partial<Prisma.RobotPackageReadinessUpdateInput> & {
      specialistId?: string;
      physicalProductStatus?: RobotPhysicalStatus;
    },
    userId: string,
    organizationId: string,
  ) {
    const tenAccessoriesProvided =
      'hasRobot' in data || 'hasBattery' in data || 'hasRemote' in data;
    return this.prisma.$transaction(async (tx) => {
      const result = await tx.robotPackageReadiness.upsert({
        where: { robotUnitId },
        update: { ...data },
        create: {
          robotUnitId,
          ...(data as any),
          organizationId,
          createdById: userId,
        },
      });
      // 所有配件齐齐 + completedAt 已填 → 触发 readiness_completed
      if (
        tenAccessoriesProvided &&
        result.hasRobot &&
        result.hasBattery &&
        result.hasRemote &&
        result.hasUsaPowerCable &&
        result.hasCnCableWithAdapter &&
        result.hasPowerSupply &&
        result.hasChargingDock &&
        result.hasFootPads &&
        result.hasToolsKit &&
        result.hasPaperwork
      ) {
        if (!result.completedAt) {
          await tx.robotPackageReadiness.update({
            where: { robotUnitId },
            data: { completedAt: new Date() },
          });
        }
        await tx.robotLifecycleEvent.create({
          data: {
            robotUnitId,
            eventType: RobotLifecycleEventType.readiness_completed,
            actorUserId: userId,
            relatedType: RobotEventRelatedType.READINESS,
            relatedId: result.id,
            payload: {
              specialistId: data.specialistId,
              physicalProductStatus: data.physicalProductStatus,
              readyAt: new Date().toISOString(),
            } as Prisma.InputJsonValue,
            occurredAt: new Date(),
            organizationId,
            createdById: userId,
          },
        });
      }
      return result;
    });
  }

  findReadiness(robotUnitId: string) {
    return this.prisma.robotPackageReadiness.findUnique({ where: { robotUnitId } });
  }

  // ---- Inspection ----

  async addInspection(
    robotUnitId: string,
    input: {
      inspectionNo?: number;
      inspectorId?: string;
      issue?: string;
      issueTagCode?: string;
      resolvedAt?: Date | string;
      resolvedById?: string;
    },
    userId: string,
    organizationId: string,
  ) {
    return this.prisma.$transaction(async (tx) => {
      // inspectionNo 未传则 backend 自动派生（max+1）。
      // 前端永远不应该自己算，因为 list/detail 默认不 join inspections relation，
      // 用 `(unit.inspections?.length ?? 0) + 1` 永远 = 1 → 重测会撞 unique。
      let inspectionNo = input.inspectionNo;
      if (inspectionNo == null) {
        const last = await tx.inspectionRecord.findFirst({
          where: { robotUnitId },
          orderBy: { inspectionNo: 'desc' },
          select: { inspectionNo: true },
        });
        inspectionNo = (last?.inspectionNo ?? 0) + 1;
      }
      const rec = await tx.inspectionRecord.create({
        data: {
          robotUnitId,
          inspectionNo,
          inspectedAt: new Date(),
          inspectorId: input.inspectorId,
          issue: input.issue,
          issueTagCode: input.issueTagCode,
          resolvedAt: input.resolvedAt ? new Date(input.resolvedAt) : null,
          resolvedById: input.resolvedById,
          organizationId,
          createdById: userId,
        },
      });
      await tx.robotLifecycleEvent.create({
        data: {
          robotUnitId,
          eventType: RobotLifecycleEventType.inspection_logged,
          actorUserId: userId,
          relatedType: RobotEventRelatedType.INSPECTION,
          relatedId: rec.id,
          payload: { inspectionNo, issue: input.issue, issueTagCode: input.issueTagCode } as Prisma.InputJsonValue,
          occurredAt: rec.inspectedAt,
          organizationId,
          createdById: userId,
        },
      });
      return rec;
    });
  }

  listInspections(robotUnitId: string) {
    return this.prisma.inspectionRecord.findMany({
      where: { robotUnitId },
      orderBy: { inspectionNo: 'asc' },
    });
  }

  // ---- LogisticsLeg ----

  async addLogisticsLeg(
    robotUnitId: string,
    input: {
      legNo: number;
      fromLocationId?: string;
      toLocationId?: string;
      departedAt?: Date | string;
      arrivedAt?: Date | string;
      logisticsStatus: LogisticsStatus;
      importDeclarationTypeCode?: string;
      tariffTypeCode?: string;
      shippingReceiptAttachmentId?: string;
      additionalNotes?: string;
    },
    userId: string,
    organizationId: string,
  ) {
    return this.prisma.logisticsLeg.create({
      data: {
        robotUnitId,
        legNo: input.legNo,
        fromLocationId: input.fromLocationId,
        toLocationId: input.toLocationId,
        departedAt: input.departedAt ? new Date(input.departedAt) : null,
        arrivedAt: input.arrivedAt ? new Date(input.arrivedAt) : null,
        logisticsStatus: input.logisticsStatus,
        importDeclarationTypeCode: input.importDeclarationTypeCode,
        tariffTypeCode: input.tariffTypeCode,
        shippingReceiptAttachmentId: input.shippingReceiptAttachmentId,
        additionalNotes: input.additionalNotes,
        organizationId,
        createdById: userId,
      },
    });
  }

  listLogisticsLegs(robotUnitId: string) {
    return this.prisma.logisticsLeg.findMany({
      where: { robotUnitId },
      orderBy: { legNo: 'asc' },
    });
  }

  // ---- ComplianceCheck ----

  async upsertCompliance(
    robotUnitId: string,
    input: {
      dateReady?: Date | string;
      stickerStatus?: StickerStatus;
      fccStatus?: FccStatus;
      complianceNotes?: string;
    },
    userId: string,
    organizationId: string,
  ) {
    return this.prisma.complianceCheck.upsert({
      where: { robotUnitId },
      update: {
        dateReady: input.dateReady ? new Date(input.dateReady) : undefined,
        stickerStatus: input.stickerStatus,
        fccStatus: input.fccStatus,
        complianceNotes: input.complianceNotes,
        lastUpdatedAt: new Date(),
      },
      create: {
        robotUnitId,
        dateReady: input.dateReady ? new Date(input.dateReady) : null,
        stickerStatus: input.stickerStatus,
        fccStatus: input.fccStatus,
        complianceNotes: input.complianceNotes,
        lastUpdatedAt: new Date(),
        organizationId,
        createdById: userId,
      },
    });
  }

  findCompliance(robotUnitId: string) {
    return this.prisma.complianceCheck.findUnique({ where: { robotUnitId } });
  }
}
