import type { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import {
  formatCustomerAddressForAdmin,
  formatSelectedAddressForAdmin,
  formatCargoForAdmin,
} from "@/modules/alert/alert-presentation";
import type { NormalizedCargo } from "@/modules/quote/types";

export const QUOTE_QUERY_LOG_MAX_ROWS = 1000;

export type QuoteQueryOutcome = "processing" | "success" | "failed" | "stale";

function buildCargoJson(cargo: NormalizedCargo): Prisma.InputJsonValue {
  return {
    weight_lb: cargo.weightLb,
    dim_l_in: cargo.dimLIn,
    dim_w_in: cargo.dimWIn,
    dim_h_in: cargo.dimHIn,
    pallet_count: cargo.palletCount,
    cargo_type: cargo.cargoType,
  };
}

async function trimQuoteQueryLogs(): Promise<void> {
  const total = await prisma.quoteQueryLog.count();
  if (total <= QUOTE_QUERY_LOG_MAX_ROWS) {
    return;
  }
  const excess = total - QUOTE_QUERY_LOG_MAX_ROWS;
  const oldest = await prisma.quoteQueryLog.findMany({
    orderBy: { createdAt: "asc" },
    take: excess,
    select: { id: true },
  });
  if (oldest.length === 0) {
    return;
  }
  await prisma.quoteQueryLog.deleteMany({
    where: { id: { in: oldest.map((row) => row.id) } },
  });
}

/** 询价提交时写入查询审计（processing） */
export async function recordQuoteQueryStart(
  cargo: NormalizedCargo,
  quoteId: string,
  outcome: QuoteQueryOutcome = "processing",
): Promise<void> {
  try {
    await prisma.quoteQueryLog.upsert({
      where: { quoteId },
      create: {
        quoteId,
        requestId: cargo.requestId,
        customerId: cargo.customerId,
        pickupJson: cargo.pickupAddress as Prisma.InputJsonValue,
        deliveryJson: cargo.deliveryAddress as Prisma.InputJsonValue,
        cargoJson: buildCargoJson(cargo),
        outcome,
      },
      update: {
        outcome,
      },
    });
    await trimQuoteQueryLogs();
  } catch (error) {
    console.error("[quote-query-log] 写入失败:", error);
  }
}

/** 询价完成或失败时更新审计 */
export async function recordQuoteQueryOutcome(
  quoteId: string,
  outcome: QuoteQueryOutcome,
  options?: {
    failureReason?: string | null;
    errorCode?: string | null;
    sourceType?: string | null;
    tierCount?: number | null;
  },
): Promise<void> {
  try {
    await prisma.quoteQueryLog.updateMany({
      where: { quoteId },
      data: {
        outcome,
        failureReason: options?.failureReason ?? null,
        errorCode: options?.errorCode ?? null,
        sourceType: options?.sourceType ?? null,
        tierCount: options?.tierCount ?? null,
        completedAt: outcome === "processing" ? null : new Date(),
      },
    });
  } catch (error) {
    console.error("[quote-query-log] 更新失败:", error);
  }
}

export type QuoteQueryLogDto = {
  quote_id: string;
  request_id: string;
  customer_id: string;
  outcome: QuoteQueryOutcome;
  failure_reason: string | null;
  error_code: string | null;
  source_type: string | null;
  tier_count: number | null;
  pickup_customer: string;
  pickup_selected: string;
  delivery_customer: string;
  delivery_selected: string;
  cargo_summary: string;
  created_at: string;
  completed_at: string | null;
};

function cargoJsonToRecord(cargoJson: unknown) {
  if (!cargoJson || typeof cargoJson !== "object") {
    return null;
  }
  const c = cargoJson as Record<string, unknown>;
  return {
    weightLb: c.weight_lb as number | undefined,
    palletCount: c.pallet_count as number | undefined,
    cargoType: c.cargo_type as string | undefined,
    dimLIn: c.dim_l_in as number | undefined,
    dimWIn: c.dim_w_in as number | undefined,
    dimHIn: c.dim_h_in as number | undefined,
  };
}

function serializeQueryLog(row: {
  quoteId: string;
  requestId: string;
  customerId: string;
  outcome: string;
  failureReason: string | null;
  errorCode: string | null;
  sourceType: string | null;
  tierCount: number | null;
  pickupJson: unknown;
  deliveryJson: unknown;
  cargoJson: unknown;
  createdAt: Date;
  completedAt: Date | null;
}): QuoteQueryLogDto {
  const cargoRecord = cargoJsonToRecord(row.cargoJson);
  return {
    quote_id: row.quoteId,
    request_id: row.requestId,
    customer_id: row.customerId,
    outcome: row.outcome as QuoteQueryOutcome,
    failure_reason: row.failureReason,
    error_code: row.errorCode,
    source_type: row.sourceType,
    tier_count: row.tierCount,
    pickup_customer: formatCustomerAddressForAdmin(row.pickupJson),
    pickup_selected: formatSelectedAddressForAdmin(row.pickupJson),
    delivery_customer: formatCustomerAddressForAdmin(row.deliveryJson),
    delivery_selected: formatSelectedAddressForAdmin(row.deliveryJson),
    cargo_summary: formatCargoForAdmin(row.cargoJson, cargoRecord as never),
    created_at: row.createdAt.toISOString(),
    completed_at: row.completedAt?.toISOString() ?? null,
  };
}

export async function listQuoteQueryLogs(options: {
  page: number;
  size: number;
  customerId?: string;
  outcome?: QuoteQueryOutcome;
}): Promise<{
  list: QuoteQueryLogDto[];
  total: number;
  page: number;
  size: number;
}> {
  const where = {
    ...(options.customerId ? { customerId: options.customerId } : {}),
    ...(options.outcome ? { outcome: options.outcome } : {}),
  };

  const [total, rows] = await Promise.all([
    prisma.quoteQueryLog.count({ where }),
    prisma.quoteQueryLog.findMany({
      where,
      orderBy: { createdAt: "desc" },
      skip: (options.page - 1) * options.size,
      take: options.size,
    }),
  ]);

  return {
    list: rows.map((row) => serializeQueryLog(row)),
    total,
    page: options.page,
    size: options.size,
  };
}
