import { Prisma } from "@prisma/client";
import { writeAlert } from "@/modules/alert/service";
import { getL3 } from "@/modules/cache/redis-cache";
import { QUOTE_VALIDITY_MS } from "@/lib/constants/quote";
import { prisma } from "@/lib/prisma";
import { getConfidenceScore } from "@/modules/quote/confidence";
import {
  applyMarkupToQuotes,
  getMarkupRule,
  type RawQuoteTier,
} from "@/modules/pricing/engine";
import { prepareMotherShipStorageQuotes } from "@/modules/quote/quote-completeness";
import { recordPostDone, safeRecord } from "@/modules/metrics/collector";
import { RpaError } from "@/modules/rpa/errors";
import { isEntryErrorCode } from "@/modules/rpa/error-mapper";
import {
  resolveQuoteFailureCode,
  resolveQuoteFailureMessage,
  truncateQuoteErrorMessage,
  type QuoteFailureCode,
} from "@/modules/quote/quote-error-messages";
import type { L2CachePayload } from "@/modules/quote/types";
import { recordQuoteQueryOutcome } from "@/modules/quote/query-log";

export type FallbackResult =
  | {
      status: "done";
      sourceType: "stale";
      isRealtime: false;
      quotes: ReturnType<typeof applyMarkupToQuotes>;
    }
  | {
      status: "failed";
      errorCode: QuoteFailureCode;
      errorMessage: string;
    };

/** 入口类错误不重试，直接降级（task-129） */
export function shouldConsumeRpaRetry(error: unknown): boolean {
  if (error instanceof RpaError && isEntryErrorCode(error.code)) {
    return false;
  }
  return true;
}

/**
 * RPA 失败 → L3 降级完整编排（task-092）
 * 不抛异常阻断主流程
 */
export async function handleRpaFailure(
  quoteId: string,
  cargoHash: string,
  customerId: string,
  error: unknown,
  options?: { skipStaleFallback?: boolean },
): Promise<FallbackResult> {
  const l3 = options?.skipStaleFallback
    ? null
    : await getL3<L2CachePayload>(cargoHash);
  const errorMessage =
    error instanceof Error ? error.message : String(error ?? "unknown");
  const failureCode = resolveQuoteFailureCode(error);
  const userMessage = truncateQuoteErrorMessage(
    resolveQuoteFailureMessage(error, failureCode),
  );

  if (l3?.quotes?.length) {
    let uiQuotes: RawQuoteTier[];
    try {
      uiQuotes = prepareMotherShipStorageQuotes(l3.quotes as RawQuoteTier[]);
    } catch {
      await prisma.quoteRecord.update({
        where: { quoteId },
        data: {
          status: "failed",
          errorCode: failureCode,
          errorMessage: userMessage,
          sourceType: null,
          isRealtime: false,
        },
      });
      await writeAlert("RPA_FAILED", {
        quoteId,
        cargoHash,
        detail: { reason: "L3 数据不完整", error: errorMessage },
      });
      await recordQuoteQueryOutcome(quoteId, "failed", {
        failureReason: userMessage,
        errorCode: "QUOTE_UNAVAILABLE",
      });
      return {
        status: "failed",
        errorCode: "QUOTE_UNAVAILABLE",
        errorMessage: userMessage,
      };
    }

    const markupRule = await getMarkupRule(customerId);
    const markedQuotes = applyMarkupToQuotes(uiQuotes, markupRule);
    const validUntil = new Date(Date.now() + QUOTE_VALIDITY_MS);

    await prisma.quoteRecord.update({
      where: { quoteId },
      data: {
        status: "done",
        sourceType: "stale",
        isRealtime: false,
        confidenceScore: getConfidenceScore("stale"),
        markupPercent:
          markupRule.type === "percent" ? markupRule.percent : 0,
        quotesJson: markedQuotes as unknown as Prisma.InputJsonValue,
        validUntil,
        errorCode: null,
      },
    });

    await writeAlert("STALE_FALLBACK", {
      quoteId,
      cargoHash,
      detail: { reason: errorMessage, customer_id: customerId },
    });

    await recordQuoteQueryOutcome(quoteId, "stale", {
      failureReason: userMessage,
      sourceType: "stale",
      tierCount: markedQuotes.length,
    });

    safeRecord(() =>
      recordPostDone({
        quoteId,
        sourceType: "stale",
        isRealtime: false,
      }),
    );

    return {
      status: "done",
      sourceType: "stale",
      isRealtime: false,
      quotes: markedQuotes,
    };
  }

  await prisma.quoteRecord.update({
    where: { quoteId },
    data: {
      status: "failed",
      errorCode: failureCode,
      errorMessage: userMessage,
      isRealtime: false,
    },
  });

  await writeAlert("RPA_FAILED", {
    quoteId,
    cargoHash,
    detail: { reason: errorMessage, customer_id: customerId },
  });

  await recordQuoteQueryOutcome(quoteId, "failed", {
    failureReason: userMessage,
    errorCode: failureCode,
  });

  return { status: "failed", errorCode: failureCode, errorMessage: userMessage };
}
