import { Prisma } from "@prisma/client";
import { QUOTE_VALIDITY_MS } from "@/lib/constants/quote";
import { prisma } from "@/lib/prisma";
import { getMarkupRule } from "@/modules/pricing/engine";
import { getConfidenceScore } from "@/modules/quote/confidence";
import { handleRpaFailure } from "@/modules/quote/fallback-orchestrator";
import type { Priority1QuoteJobData } from "@/modules/priority1/rpa-queue";
import { buildPriority1StoredQuotes } from "@/modules/priority1/quote-storage";
import { RpaError } from "@/modules/rpa/errors";
import { recordPostDone, safeRecord } from "@/modules/metrics/collector";
import {
  closeCircuit,
  isCircuitOpen,
  recordRpaFailure,
  recordRpaSuccess,
} from "@/modules/cache/circuit-breaker";
import { PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE } from "@/modules/priority1/constants";
import { PRIORITY1_MANUAL_FOLLOWUP_MESSAGE } from "@/workers/rpa/priority1/quote-extract";
import { runPriority1QuoteRpa } from "@/workers/rpa/priority1/run-quote";
import { heartbeat, isWorkerPaused } from "@/workers/rpa/worker-state";

async function completePriority1ManualFollowup(
  quoteId: string,
  message: string,
): Promise<void> {
  await prisma.quoteRecord.update({
    where: { quoteId },
    data: {
      status: "done",
      sourceType: "rpa",
      isRealtime: true,
      confidenceScore: getConfidenceScore("rpa"),
      markupPercent: 0,
      quotesJson: Prisma.JsonNull,
      validUntil: null,
      errorCode: PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE,
      errorMessage: message,
    },
  });

  safeRecord(() =>
    recordPostDone({
      quoteId,
      sourceType: "rpa",
      isRealtime: true,
    }),
  );
}

export async function processPriority1QuoteJob(
  data: Priority1QuoteJobData,
  workerId: string,
  options?: { isFinalAttempt?: boolean },
): Promise<void> {
  await heartbeat(workerId);

  if (await isCircuitOpen()) {
    throw new RpaError("PAGE_LOAD_TIMEOUT", "RPA 熔断中，暂缓消费", {
      retryable: true,
    });
  }

  if (await isWorkerPaused(workerId)) {
    throw new RpaError("RPA_CAPTCHA", "Worker 已暂停", { retryable: true });
  }

  try {
    const result = await runPriority1QuoteRpa(data.input);
    if (!result.ok) {
      throw new RpaError(
        "RPA_DATA_INVALID",
        result.errorMessage ?? "Priority1 报价提取失败",
        { retryable: true },
      );
    }

    if (result.quoteOutcome === "manual_followup") {
      await completePriority1ManualFollowup(
        data.quoteId,
        result.message ?? PRIORITY1_MANUAL_FOLLOWUP_MESSAGE,
      );
      await recordRpaSuccess();
      await closeCircuit();
      return;
    }

    if (result.quotes.length === 0) {
      throw new RpaError(
        "RPA_DATA_INVALID",
        result.errorMessage ?? "Priority1 报价提取失败",
        { retryable: true },
      );
    }

    const markupRule = await getMarkupRule(data.customerId);
    const storedQuotes = buildPriority1StoredQuotes(
      result.quotes,
      markupRule,
      data.input.shipmentType,
    );
    const validUntil = new Date(Date.now() + QUOTE_VALIDITY_MS);

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

    safeRecord(() =>
      recordPostDone({
        quoteId: data.quoteId,
        sourceType: "rpa",
        isRealtime: true,
      }),
    );
    await recordRpaSuccess();
    await closeCircuit();
  } catch (error) {
    await recordRpaFailure();

    const isFinalAttempt = options?.isFinalAttempt ?? true;
    const canRetry =
      error instanceof RpaError &&
      error.retryable &&
      !isFinalAttempt;

    if (canRetry) throw error;

    await handleRpaFailure(
      data.quoteId,
      data.cargoHash,
      data.customerId,
      error,
      { skipStaleFallback: true },
    );

    if (error instanceof RpaError && !error.retryable) return;
    throw error;
  }
}
