import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  Prisma,
  RobotLifecycleStage,
  PaymentStatus,
  QualityLabelStatus,
  DeliveryFormStatus,
} from '@prisma/client';

export type GuardResult = { ok: boolean; reasons?: string[] };

/**
 * 13 个生命周期 Guard 函数 — 来源 最终字段设计.md §9b.2
 *
 * service 层硬编码（不立 GuardDefinition 表，per standard 16 §4.5 默认规则）。
 * Guard 失败抛业务异常，前端显示原因，不切 stage 不写 event。
 *
 * Happy path 完整实现；少数异常分支（如 PR4 业务方 review 后明确）当前 placeholder。
 */
@Injectable()
export class LifecycleGuardsService {
  private readonly logger = new Logger(LifecycleGuardsService.name);

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 路由器：根据 from → to 触发对应 guard
   * 返回所有失败原因（聚合），全部通过则 ok=true
   */
  async check(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
    fromStage: RobotLifecycleStage,
    toStage: RobotLifecycleStage,
  ): Promise<GuardResult> {
    const checks: Array<Promise<GuardResult>> = [];

    // A. 流程图揭示的控制门（7 条）
    if (
      fromStage === RobotLifecycleStage.WAREHOUSE_AT_W1_PDI &&
      toStage === RobotLifecycleStage.WAREHOUSE_MODIFICATION
    ) {
      checks.push(this.checkFunctionTest(tx, robotUnitId));
    }
    // 07 RECEIVED hard gate：占位 SN 必须先激活（v3 业务设计核心）
    if (
      fromStage === RobotLifecycleStage.LOGISTICS_CUSTOMS_CLEARED &&
      toStage === RobotLifecycleStage.WAREHOUSE_RECEIVED
    ) {
      checks.push(this.checkPlaceholderActivated(tx, robotUnitId));
    }
    if (
      fromStage === RobotLifecycleStage.WAREHOUSE_MODIFICATION &&
      toStage === RobotLifecycleStage.WAREHOUSE_BRANDED_READY
    ) {
      checks.push(this.checkConversionValidated(tx, robotUnitId));
    }
    if (
      fromStage === RobotLifecycleStage.DELIVERY_READY &&
      toStage === RobotLifecycleStage.DELIVERY_DELIVERED
    ) {
      checks.push(this.checkDeliveryValidation(tx, robotUnitId));
      checks.push(this.checkPGIReady(tx, robotUnitId));
    }
    if (
      fromStage === RobotLifecycleStage.SALES_RESERVED &&
      toStage === RobotLifecycleStage.SALES_PAYMENT_VALIDATED
    ) {
      checks.push(this.checkG5Payment(tx, robotUnitId));
    }
    if (
      fromStage === RobotLifecycleStage.DELIVERY_DELIVERED &&
      toStage === RobotLifecycleStage.AFTERSALES_RETURN_INITIATED
    ) {
      checks.push(this.checkRMAEligible(tx, robotUnitId));
    }
    if (
      fromStage === RobotLifecycleStage.AFTERSALES_UNDER_REPAIR &&
      toStage === RobotLifecycleStage.AFTERSALES_REPAIRED
    ) {
      checks.push(this.checkQuoteApproved(tx, robotUnitId));
    }

    // B. 业务实体硬约束（6 条）
    if (toStage === RobotLifecycleStage.SALES_RESERVED) {
      checks.push(this.checkReserveRequiresBranded(tx, robotUnitId, fromStage));
    }
    if (toStage === RobotLifecycleStage.CLOSED) {
      checks.push(this.checkClosedNeedsDisposal(tx, robotUnitId));
    }
    if (toStage === RobotLifecycleStage.RENTAL_ACTIVE) {
      checks.push(this.checkRentalNeedsContract(tx, robotUnitId));
    }
    if (
      fromStage === RobotLifecycleStage.DELIVERY_DELIVERED &&
      toStage === RobotLifecycleStage.RETURNED
    ) {
      checks.push(this.checkD2EligibleWindow(tx, robotUnitId));
    }

    if (checks.length === 0) return { ok: true };

    const results = await Promise.all(checks);
    const failures = results.filter((r) => !r.ok);
    if (failures.length === 0) return { ok: true };
    return {
      ok: false,
      reasons: failures.flatMap((r) => r.reasons ?? []),
    };
  }

  // ============ A. 控制门 ============

  async checkFunctionTest(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    // 至少一条 InspectionRecord 已 resolvedAt
    const ok = await (tx as PrismaService).inspectionRecord.findFirst({
      where: { robotUnitId, resolvedAt: { not: null } },
      select: { id: true },
    });
    return ok ? { ok: true } : { ok: false, reasons: ['功能测试未完成 / 未通过'] };
  }

  async checkConversionValidated(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const reasons: string[] = [];
    const [labels, readiness] = await Promise.all([
      (tx as PrismaService).qualityLabelRecord.findMany({
        where: { robotUnitId },
        select: { labelTypeCode: true, status: true },
      }),
      (tx as PrismaService).robotPackageReadiness.findUnique({
        where: { robotUnitId },
        select: { completedAt: true },
      }),
    ]);
    const verifiedCount = labels.filter((l) => l.status === QualityLabelStatus.VERIFIED).length;
    if (labels.length < 7) reasons.push(`质量标签未齐（当前 ${labels.length}/7）`);
    if (verifiedCount < 7) reasons.push(`质量标签未全部验证（${verifiedCount}/7 VERIFIED）`);
    if (!readiness?.completedAt) reasons.push('配件清点未完成');
    return reasons.length ? { ok: false, reasons } : { ok: true };
  }

  async checkDeliveryValidation(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const fulfillment = await (tx as PrismaService).deliveryFulfillment.findFirst({
      where: { robotUnitId },
      orderBy: { deliveredAt: 'desc' },
      select: { signedFormStatus: true, deliveryRequestId: true },
    });
    if (!fulfillment) return { ok: false, reasons: ['缺少 DeliveryFulfillment 记录'] };
    if (fulfillment.signedFormStatus !== DeliveryFormStatus.SIGNED) {
      return { ok: false, reasons: ['交付签字单未签署'] };
    }
    return { ok: true };
  }

  async checkG5Payment(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const paid = await (tx as PrismaService).paymentRecord.findFirst({
      where: { robotUnitId, paymentStatus: PaymentStatus.PAID },
      select: { id: true },
    });
    if (paid) return { ok: true };
    return { ok: false, reasons: ['销售订单付款未到账（G5 硬阻塞）'] };
  }

  async checkPGIReady(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const [fulfillment, paid] = await Promise.all([
      (tx as PrismaService).deliveryFulfillment.findFirst({
        where: { robotUnitId },
        orderBy: { deliveredAt: 'desc' },
        select: { acceptanceFormStatus: true },
      }),
      (tx as PrismaService).paymentRecord.findFirst({
        where: { robotUnitId, paymentStatus: PaymentStatus.PAID },
        select: { id: true },
      }),
    ]);
    if (!fulfillment) return { ok: false, reasons: ['缺少 DeliveryFulfillment 记录'] };
    if (fulfillment.acceptanceFormStatus !== DeliveryFormStatus.SIGNED) {
      return { ok: false, reasons: ['交付验收单未签署 (PGI 阻塞)'] };
    }
    if (!paid) return { ok: false, reasons: ['款项未到账 (PGI 阻塞)'] };
    return { ok: true };
  }

  async checkRMAEligible(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    // 必须存在 open 的 ServiceTicket
    const ticket = await (tx as PrismaService).serviceTicket.findFirst({
      where: { robotUnitId, closedAt: null },
      select: { id: true },
    });
    if (!ticket) return { ok: false, reasons: ['无未结售后工单，不允许发起 RMA'] };
    return { ok: true };
  }

  async checkQuoteApproved(
    _tx: Prisma.TransactionClient | PrismaService,
    _robotUnitId: string,
  ): Promise<GuardResult> {
    // 当前放行：in-warranty 路径无需 QUOTE_APPROVAL；OOW 路径的明确拒绝条件待业务方
    // review 后实施（PR4 业务方 PRD review 输入），此处先 placeholder ok=true。
    return { ok: true };
  }

  // ============ B. 业务实体硬约束 ============

  async checkPOHasSupplier(
    tx: Prisma.TransactionClient | PrismaService,
    poData: { supplierId: string },
  ): Promise<GuardResult> {
    if (!poData.supplierId) return { ok: false, reasons: ['采购单缺少 supplier'] };
    const supplier = await (tx as PrismaService).$queryRaw<Array<{ id: string }>>`
      SELECT id FROM platform_master.suppliers WHERE id = ${poData.supplierId}::uuid AND deleted_at IS NULL LIMIT 1
    `;
    return supplier.length ? { ok: true } : { ok: false, reasons: ['supplier 不存在或已删除'] };
  }

  async checkSONeedsCustomer(
    tx: Prisma.TransactionClient | PrismaService,
    soData: { customerId: string; currencyCode: string },
  ): Promise<GuardResult> {
    if (!soData.customerId) return { ok: false, reasons: ['销售单缺少 customer'] };
    const customer = await (tx as PrismaService).$queryRaw<Array<{ id: string }>>`
      SELECT id FROM platform_master.customers WHERE id = ${soData.customerId}::uuid AND deleted_at IS NULL LIMIT 1
    `;
    return customer.length ? { ok: true } : { ok: false, reasons: ['customer 不存在或已删除'] };
  }

  async checkReserveRequiresBranded(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
    fromStage: RobotLifecycleStage,
  ): Promise<GuardResult> {
    const allowedFrom: RobotLifecycleStage[] = [
      RobotLifecycleStage.WAREHOUSE_BRANDED_READY,
      RobotLifecycleStage.WAREHOUSE_AT_W2_RLE,
    ];
    if (!allowedFrom.includes(fromStage)) {
      return {
        ok: false,
        reasons: ['进入 SALES_RESERVED 必须来自 WAREHOUSE_BRANDED_READY 或 WAREHOUSE_AT_W2_RLE'],
      };
    }
    // SalesOrderLine.robotUnitId 已绑定
    const line = await (tx as PrismaService).salesOrderLine.findFirst({
      where: { robotUnitId },
      select: { id: true },
    });
    return line ? { ok: true } : { ok: false, reasons: ['尚未绑定到 SalesOrderLine'] };
  }

  async checkClosedNeedsDisposal(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const unit = await (tx as PrismaService).robotUnit.findUnique({
      where: { id: robotUnitId },
      select: { disposalType: true, retiredAt: true },
    });
    if (!unit) return { ok: false, reasons: ['robot unit 不存在'] };
    const reasons: string[] = [];
    if (!unit.disposalType) reasons.push('CLOSED 前必须填 disposalType');
    if (!unit.retiredAt) reasons.push('CLOSED 前必须填 retiredAt');
    return reasons.length ? { ok: false, reasons } : { ok: true };
  }

  async checkRentalNeedsContract(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const rental = await (tx as PrismaService).rentalAgreement.findFirst({
      where: { robotUnitId, status: 'ACTIVE' },
      select: { id: true },
    });
    return rental ? { ok: true } : { ok: false, reasons: ['进入 RENTAL_ACTIVE 缺少有效 RentalAgreement'] };
  }

  async checkD2EligibleWindow(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const fulfillment = await (tx as PrismaService).deliveryFulfillment.findFirst({
      where: { robotUnitId },
      orderBy: { deliveredAt: 'desc' },
      select: { deliveredAt: true },
    });
    if (!fulfillment?.deliveredAt) {
      return { ok: false, reasons: ['未找到交付记录'] };
    }
    const days = (Date.now() - fulfillment.deliveredAt.getTime()) / 86400_000;
    if (days > 7) return { ok: false, reasons: [`D2 退货窗口已过（${Math.floor(days)} 天 > 7 天）`] };
    return { ok: true };
  }

  /**
   * 07 RECEIVED 推进 hard gate：占位 SN 必须先激活（POST :id/activate-sn）
   *
   * v3 业务设计核心：占位 SN 在 PO 阶段批量预留，07 收货时扫供应商物理标签激活换正式 SN。
   * 推进到 WAREHOUSE_RECEIVED 时如果 ffsn 还是占位（含 -LINE-NNN 后缀 + placeholderSnOrig 为空），
   * 则拒绝推进，提示先调 activate-sn endpoint。
   */
  async checkPlaceholderActivated(
    tx: Prisma.TransactionClient | PrismaService,
    robotUnitId: string,
  ): Promise<GuardResult> {
    const unit = await (tx as PrismaService).robotUnit.findUnique({
      where: { id: robotUnitId },
      select: { ffsn: true, placeholderSnOrig: true, supplierSn: true },
    });
    if (!unit) return { ok: false, reasons: ['Unit not found'] };
    const isPlaceholder = /-LINE-\d+$/.test(unit.ffsn) && !unit.placeholderSnOrig;
    if (isPlaceholder) {
      return {
        ok: false,
        reasons: [
          'PLACEHOLDER_NOT_ACTIVATED: 推进到 WAREHOUSE_RECEIVED 前必须先激活占位 SN（POST /robot-manager/:id/activate-sn 扫供应商物理标签）',
        ],
      };
    }
    return { ok: true };
  }
}
