import { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { markQuoteStarted, safeRecord } from "@/modules/metrics/collector";
import { generateQuoteId, handleQuoteIdConflict, isQuoteIdUniqueConflict } from "@/modules/quote/quote-id";
import type { Priority1DemoInput } from "@/workers/rpa/priority1/demo-input";
import { hashPriority1Input } from "@/modules/priority1/hash";
import { enqueuePriority1QuoteJob } from "@/modules/priority1/rpa-queue";
import { validatePriority1QuoteInput } from "@/modules/priority1/validation";

export class Priority1EnqueueError extends Error {
  readonly code = "QUOTE_UNAVAILABLE" as const;

  constructor(message: string) {
    super(message);
    this.name = "Priority1EnqueueError";
  }
}

export type Priority1SubmitResult = {
  quote_id: string;
  status: "processing";
};

function zipAddressJson(
  zip: string,
  input: Priority1DemoInput,
  side: "origin" | "destination",
): Prisma.InputJsonValue {
  return {
    street: "",
    city: "",
    state: "",
    zip,
    place_id: "",
    formatted_address: zip,
    selected_from_suggestions: false,
    ...(side === "origin"
      ? {
          priority1_shipment_type: input.shipmentType,
          priority1_pickup_date: input.pickupDate,
          priority1_commodity: input.commodity,
        }
      : {}),
  };
}

function recordFields(input: Priority1DemoInput) {
  const weight = Number(input.weightLb) || 0;
  const length = Number(input.lengthIn) || 48;
  const width = Number(input.widthIn) || 40;
  const height = Number(input.heightIn) || 48;
  const pallets = Number(input.palletCount) || 1;
  const cargoType =
    input.shipmentType === "ltl"
      ? input.packaging.toLowerCase()
      : input.commodity.toLowerCase().replace(/\s+/g, "_").slice(0, 32);

  return {
    weightLb: weight,
    dimLIn: length,
    dimWIn: width,
    dimHIn: height,
    palletCount: pallets,
    cargoType: cargoType || "general_freight",
  };
}

/** Priority1 询价入队 */
export async function submitPriority1Quote(body: unknown): Promise<Priority1SubmitResult> {
  const parsed = validatePriority1QuoteInput(body);
  const { request_id, customer_id, ...input } = parsed;
  const cargoHash = hashPriority1Input(input);
  let quoteId = await generateQuoteId();
  const dims = recordFields(input);

  const baseRecord = {
    requestId: request_id,
    customerId: customer_id,
    cargoHash,
    status: "processing" as const,
    pickupJson: zipAddressJson(input.originZip, input, "origin"),
    deliveryJson: zipAddressJson(input.destinationZip, input, "destination"),
    weightLb: dims.weightLb,
    dimLIn: dims.dimLIn,
    dimWIn: dims.dimWIn,
    dimHIn: dims.dimHIn,
    palletCount: dims.palletCount,
    cargoType: dims.cargoType,
    quotesJson: Prisma.JsonNull,
  };

  try {
    await prisma.quoteRecord.create({
      data: { quoteId, ...baseRecord },
    });
  } catch (error) {
    if (!isQuoteIdUniqueConflict(error)) {
      throw error;
    }
    quoteId = await generateQuoteId();
    try {
      await prisma.quoteRecord.create({
        data: { quoteId, ...baseRecord },
      });
    } catch (retryError) {
      if (isQuoteIdUniqueConflict(retryError)) {
        await handleQuoteIdConflict(quoteId, customer_id);
      }
      throw retryError;
    }
  }

  try {
    await enqueuePriority1QuoteJob({
      quoteId,
      requestId: request_id,
      customerId: customer_id,
      cargoHash,
      input,
    });
  } catch (error) {
    const brief = error instanceof Error ? error.message : String(error);
    console.error(`[priority1] 入队失败 quote_id=${quoteId}:`, error);
    const redisLike = /redis|REDIS_URL/i.test(brief);
    const userMessage = redisLike
      ? "Redis 不可用，无法提交 Priority1 询价（请确认 REDIS_URL 与 Worker 已启动）"
      : "Priority1 任务入队失败，请稍后重试或联系管理员";
    await prisma.quoteRecord
      .update({
        where: { quoteId },
        data: {
          status: "failed",
          errorCode: "QUOTE_UNAVAILABLE",
          errorMessage: userMessage,
        },
      })
      .catch(() => undefined);
    throw new Priority1EnqueueError(userMessage);
  }

  safeRecord(() => markQuoteStarted(quoteId));

  return { quote_id: quoteId, status: "processing" };
}
