import { Prisma } from "@prisma/client";
import { getL2, setL2, setL3 } from "@/modules/cache/redis-cache";
import { QUOTE_VALIDITY_MS } from "@/lib/constants/quote";
import { prisma } from "@/lib/prisma";
import { fetchAxelQuoteItems } from "@/lib/axel/quote-from-request";
import { isAxelDirectQuoteMode, isInlineDirectQuoteEnabled } from "@/lib/rpa/env";
import { getConfidenceScore } from "@/modules/quote/confidence";
import {
  applyMarkupToQuotes,
  getMarkupRule,
  type RawQuoteTier,
} from "@/modules/pricing/engine";
import {
  checkIdempotency,
  saveIdempotency,
} from "@/modules/quote/idempotency";
import { prepareMotherShipStorageQuotes } from "@/modules/quote/quote-completeness";
import {
  generateQuoteId,
  handleQuoteIdConflict,
  isQuoteIdUniqueConflict,
} from "@/modules/quote/quote-id";
import { enqueueQuoteJob } from "@/modules/quote/rpa-queue";
import {
  recordQuoteQueryOutcome,
  recordQuoteQueryStart,
} from "@/modules/quote/query-log";
import type {
  L2CachePayload,
  NormalizedCargo,
  QuoteSubmitResult,
} from "@/modules/quote/types";
import {
  markQuoteStarted,
  recordCacheHit,
  recordPostDone,
  recordPostTotal,
  recordRpaTriggered,
  safeRecord,
} from "@/modules/metrics/collector";
import { cargoToQuoteRequest, quoteItemsToRawTiers } from "@/modules/rpa/quote-mapper";
import { validateQuoteInput } from "@/modules/quote/validation";
import { getCustomerProviderLogin, hasCustomerProviderCredential } from "@/modules/customer/provider-credentials";

export type SubmitQuoteResponse = {
  quote_id: string;
  status: "processing" | "done";
  source_type?: "cache" | "rpa" | "stale";
  is_realtime?: boolean;
};

/** 询价主编排：校验 → L1 → L2 → 入队（task-014） */
export async function submitQuote(
  body: unknown,
): Promise<SubmitQuoteResponse> {
  const cargo = validateQuoteInput(body);
  safeRecord(() => recordPostTotal());

  const idem = await checkIdempotency(cargo.requestId);
  if (idem.hit) {
    safeRecord(() => recordCacheHit("l1"));
    const cached = idem.response as SubmitQuoteResponse;
    if (cached?.status === "done") {
      safeRecord(() =>
        recordPostDone({
          quoteId: idem.quoteId,
          sourceType: cached.source_type ?? "cache",
          isRealtime: cached.is_realtime ?? true,
        }),
      );
    }
    return {
      quote_id: idem.quoteId,
      status: (cached?.status as "processing" | "done") ?? "done",
      source_type: cached?.source_type,
      is_realtime: cached?.is_realtime,
    };
  }

  const hasMsCredInDb = await hasCustomerProviderCredential(
    cargo.customerId,
    "mothership",
  );
  const customerMsLogin = hasMsCredInDb
    ? await getCustomerProviderLogin(cargo.customerId, "mothership")
    : null;
  const envMsLogin =
    Boolean(process.env.MOTHERSHIP_EMAIL?.trim()) &&
    Boolean(process.env.MOTHERSHIP_PASSWORD?.trim());
  // 库中已绑账密或 env 账密 → 强制登录态查价（禁止匿名 Direct / L2）
  const forceLoggedInQuote = hasMsCredInDb || envMsLogin;

  if (hasMsCredInDb && !customerMsLogin) {
    console.error(
      `[quote] customerId=${cargo.customerId} 已配置 MotherShip 账密但解密失败，仍入队登录态路径（禁止 Direct）`,
    );
  } else if (forceLoggedInQuote) {
    console.log(
      `[quote] customerId=${cargo.customerId} MotherShip 登录态查价 source=${customerMsLogin ? "customer" : "env"} email=${(customerMsLogin?.email ?? process.env.MOTHERSHIP_EMAIL ?? "").slice(0, 2)}***`,
    );
  }

  // 有账密：禁止命中匿名 Direct 缓存价（TForce 档 ≠ dashboard 承运商价）
  const l2 = forceLoggedInQuote
    ? null
    : await getL2<L2CachePayload>(cargo.cargoHash);
  if (l2?.quotes?.length) {
    const result = await completeFromCache(cargo, l2);
    safeRecord(() => recordCacheHit("l2"));
    safeRecord(() =>
      recordPostDone({
        quoteId: result.quote_id,
        sourceType: "cache",
        isRealtime: true,
      }),
    );
    return result;
  }

  if (
    !forceLoggedInQuote &&
    isAxelDirectQuoteMode() &&
    isInlineDirectQuoteEnabled()
  ) {
    const inline = await tryInlineDirectQuote(cargo);
    if (inline) {
      safeRecord(() =>
        recordPostDone({
          quoteId: inline.quote_id,
          sourceType: "rpa",
          isRealtime: true,
        }),
      );
      return inline;
    }
  }

  const result = await enqueueForRpa(cargo);
  safeRecord(() => recordRpaTriggered(result.quote_id));
  return result;
}

async function completeFromCache(
  cargo: NormalizedCargo,
  l2: L2CachePayload,
): Promise<SubmitQuoteResponse> {
  const quoteId = await generateQuoteId();
  safeRecord(() => markQuoteStarted(quoteId));

  const uiQuotes = prepareMotherShipStorageQuotes(l2.quotes as RawQuoteTier[]);
  const markupRule = await getMarkupRule(cargo.customerId);
  const markedQuotes = applyMarkupToQuotes(uiQuotes, markupRule);
  const validUntil = new Date(Date.now() + QUOTE_VALIDITY_MS);

  const response: SubmitQuoteResponse = {
    quote_id: quoteId,
    status: "done",
    source_type: "cache",
    is_realtime: true,
  };

  try {
    await prisma.quoteRecord.create({
      data: {
        quoteId,
        requestId: cargo.requestId,
        customerId: cargo.customerId,
        cargoHash: cargo.cargoHash,
        status: "done",
        sourceType: "cache",
        isRealtime: true,
        confidenceScore: getConfidenceScore("cache"),
        pickupJson: cargo.pickupAddress,
        deliveryJson: cargo.deliveryAddress,
        weightLb: cargo.weightLb,
        dimLIn: cargo.dimLIn,
        dimWIn: cargo.dimWIn,
        dimHIn: cargo.dimHIn,
        palletCount: cargo.palletCount,
        cargoType: cargo.cargoType,
        quotesJson: markedQuotes as unknown as Prisma.InputJsonValue,
        markupPercent:
          markupRule.type === "percent" ? markupRule.percent : 0,
        validUntil,
      },
    });
  } catch (error) {
    if (isQuoteIdUniqueConflict(error)) {
      await handleQuoteIdConflict(quoteId, cargo.customerId);
    }
    throw error;
  }

  await saveIdempotency(
    cargo.requestId,
    cargo.customerId,
    quoteId,
    response,
  );

  await recordQuoteQueryStart(cargo, quoteId);
  await recordQuoteQueryOutcome(quoteId, "success", {
    sourceType: "cache",
    tierCount: markedQuotes.length,
  });

  return response;
}

async function tryInlineDirectQuote(
  cargo: NormalizedCargo,
): Promise<SubmitQuoteResponse | null> {
  const quoteId = await generateQuoteId();
  safeRecord(() => markQuoteStarted(quoteId));

  try {
    // 匿名 inline Direct 仅无匿名会话；有账密已在 submitQuote 跳过本路径
    const items = await fetchAxelQuoteItems(cargoToQuoteRequest(cargo));
    const rawQuotes = quoteItemsToRawTiers(items);
    const uiQuotes = prepareMotherShipStorageQuotes(rawQuotes);

    const markupRule = await getMarkupRule(cargo.customerId);
    const markedQuotes = applyMarkupToQuotes(uiQuotes, markupRule);
    const validUntil = new Date(Date.now() + QUOTE_VALIDITY_MS);
    const cachePayload = { quotes: uiQuotes };

    await setL2(cargo.cargoHash, cachePayload);
    await setL3(cargo.cargoHash, cachePayload);

    const response: SubmitQuoteResponse = {
      quote_id: quoteId,
      status: "done",
      source_type: "rpa",
      is_realtime: true,
    };

    try {
      await prisma.quoteRecord.create({
        data: {
          quoteId,
          requestId: cargo.requestId,
          customerId: cargo.customerId,
          cargoHash: cargo.cargoHash,
          status: "done",
          sourceType: "rpa",
          isRealtime: true,
          confidenceScore: getConfidenceScore("rpa"),
          pickupJson: cargo.pickupAddress,
          deliveryJson: cargo.deliveryAddress,
          weightLb: cargo.weightLb,
          dimLIn: cargo.dimLIn,
          dimWIn: cargo.dimWIn,
          dimHIn: cargo.dimHIn,
          palletCount: cargo.palletCount,
          cargoType: cargo.cargoType,
          quotesJson: markedQuotes as unknown as Prisma.InputJsonValue,
          markupPercent:
            markupRule.type === "percent" ? markupRule.percent : 0,
          validUntil,
        },
      });
    } catch (error) {
      if (isQuoteIdUniqueConflict(error)) {
        await handleQuoteIdConflict(quoteId, cargo.customerId);
      }
      throw error;
    }

    await saveIdempotency(
      cargo.requestId,
      cargo.customerId,
      quoteId,
      response,
    );

    await recordQuoteQueryStart(cargo, quoteId);
    await recordQuoteQueryOutcome(quoteId, "success", {
      sourceType: "rpa",
      tierCount: markedQuotes.length,
    });

    return response;
  } catch (error) {
    const brief = error instanceof Error ? error.message : String(error);
    console.warn(
      `[quote] inline-direct 失败，回退队列 cargo_hash=${cargo.cargoHash} reason=${brief.slice(0, 200)}`,
    );
    return null;
  }
}

async function enqueueForRpa(
  cargo: NormalizedCargo,
): Promise<SubmitQuoteResponse> {
  const quoteId = await generateQuoteId();
  const markupRule = await getMarkupRule(cargo.customerId);

  const response: SubmitQuoteResponse = {
    quote_id: quoteId,
    status: "processing",
  };

  try {
    await prisma.quoteRecord.create({
      data: {
        quoteId,
        requestId: cargo.requestId,
        customerId: cargo.customerId,
        cargoHash: cargo.cargoHash,
        status: "processing",
        isRealtime: true,
        pickupJson: cargo.pickupAddress,
        deliveryJson: cargo.deliveryAddress,
        weightLb: cargo.weightLb,
        dimLIn: cargo.dimLIn,
        dimWIn: cargo.dimWIn,
        dimHIn: cargo.dimHIn,
        palletCount: cargo.palletCount,
        cargoType: cargo.cargoType,
        markupPercent:
          markupRule.type === "percent" ? markupRule.percent : 0,
      },
    });
  } catch (error) {
    if (isQuoteIdUniqueConflict(error)) {
      await handleQuoteIdConflict(quoteId, cargo.customerId);
    }
    throw error;
  }

  await saveIdempotency(
    cargo.requestId,
    cargo.customerId,
    quoteId,
    response,
  );

  await enqueueQuoteJob({
    quoteId,
    requestId: cargo.requestId,
    customerId: cargo.customerId,
    cargoHash: cargo.cargoHash,
    cargo,
  });

  await recordQuoteQueryStart(cargo, quoteId);

  return response;
}

export type { NormalizedCargo, QuoteSubmitResult };
