/**
 * 方案 A 随机地址报价探针
 *
 * 成功标准：询价 status=done 且 tiers>=1（真实 axel/quote）
 *
 * PowerShell:
 *   npm run probe:random-address-quote
 *   $env:PROBE_RANDOM_LOOPS="5"; npm run probe:random-address-quote
 */
import { randomUUID } from "node:crypto";
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { loadDevEnv } from "@/lib/dev-env";
import { ensureNativeInfraIfNeeded } from "@/lib/infra/ensure-native-infra";
import {
  hostCreateQuote,
  hostFetchMothershipCandidates,
  hostGetQuote,
} from "@/lib/frontend/api-client";
import { applyMothershipCandidate } from "@/lib/frontend/mothership-address";
import type { MothershipAddressCandidate, QuoteRequestBody } from "@/lib/frontend/types";
import { pollQuoteUntilDone } from "@/hooks/use-quote-polling";
import { pickBestMothershipCandidate } from "./lib/pick-mothership-candidate";
import { isAnyRpaWorkerHealthy } from "@/lib/rpa/worker-health";
import { ensureRedisReady, resetRedisClient } from "@/lib/redis";

process.env.RPA_MOCK_MODE = "false";
process.env.RPA_ADDRESS_MODE = "real";
process.env.RPA_DUAL_ADDRESS_PATCH = "true";

loadDevEnv();

const BASE = process.env.PROBE_BASE_URL ?? "http://localhost:3000";
const TOKEN = "demo-host-token";
const CUSTOMER_ID = "CUST_001";
const LOOPS = Math.max(1, Number(process.env.PROBE_RANDOM_LOOPS ?? 3));
const POLL_TIMEOUT_MS = Number(
  process.env.PROBE_RANDOM_POLL_MS ?? process.env.QUOTE_TIMEOUT_MS ?? 420_000,
);

type AddressDraft = {
  street: string;
  city: string;
  state: string;
  zip: string;
};

type AddressPair = {
  id: string;
  label: string;
  pickup: Omit<AddressDraft, "zip">;
  delivery: Omit<AddressDraft, "zip">;
  cargo: {
    pallet_count: number;
    weight_lb: number;
    length_in: number;
    width_in: number;
    height_in: number;
    cargo_type: QuoteRequestBody["cargo_type"];
  };
};

const ADDRESS_POOL: AddressPair[] = [
  {
    id: "01",
    label: "洛杉矶 CA → Farmers Branch TX",
    pickup: { street: "1234 Warehouse Street", city: "Los Angeles", state: "CA" },
    delivery: { street: "5678 Distribution Way", city: "Farmers Branch", state: "TX" },
    cargo: {
      pallet_count: 2,
      weight_lb: 500,
      length_in: 48,
      width_in: 40,
      height_in: 48,
      cargo_type: "general_freight",
    },
  },
  {
    id: "02",
    label: "西雅图 WA → 迈阿密 FL",
    pickup: { street: "3131 Western Ave", city: "Seattle", state: "WA" },
    delivery: { street: "7000 NW 52nd St", city: "Miami", state: "FL" },
    cargo: {
      pallet_count: 3,
      weight_lb: 550,
      length_in: 48,
      width_in: 40,
      height_in: 45,
      cargo_type: "general_freight",
    },
  },
  {
    id: "06",
    label: "丹佛 CO → 夏洛特 NC",
    pickup: { street: "4800 Race St", city: "Denver", state: "CO" },
    delivery: { street: "9300 South Blvd", city: "Charlotte", state: "NC" },
    cargo: {
      pallet_count: 3,
      weight_lb: 450,
      length_in: 48,
      width_in: 40,
      height_in: 44,
      cargo_type: "general_freight",
    },
  },
  {
    id: "10",
    label: "西雅图 Convention Center → 迈阿密 Beach",
    pickup: {
      street: "Washington State Convention Center Main Garage, Pike Street",
      city: "Seattle",
      state: "WA",
    },
    delivery: { street: "Ocean Drive", city: "Miami Beach", state: "FL" },
    cargo: {
      pallet_count: 2,
      weight_lb: 500,
      length_in: 48,
      width_in: 40,
      height_in: 48,
      cargo_type: "general_freight",
    },
  },
  {
    id: "99",
    label: "Key West FL → Los Angeles CA",
    pickup: { street: "Duval Street", city: "Key West", state: "FL" },
    delivery: { street: "Hollywood Boulevard", city: "Los Angeles", state: "CA" },
    cargo: {
      pallet_count: 2,
      weight_lb: 503,
      length_in: 48,
      width_in: 40,
      height_in: 48,
      cargo_type: "general_freight",
    },
  },
  {
    id: "03",
    label: "芝加哥 IL → 亚特兰大 GA",
    pickup: { street: "233 S Wacker Dr", city: "Chicago", state: "IL" },
    delivery: { street: "285 Andrew Young Intl Blvd", city: "Atlanta", state: "GA" },
    cargo: {
      pallet_count: 2,
      weight_lb: 480,
      length_in: 48,
      width_in: 40,
      height_in: 48,
      cargo_type: "general_freight",
    },
  },
  {
    id: "04",
    label: "达拉斯 TX → 凤凰城 AZ",
    pickup: { street: "1500 Marilla St", city: "Dallas", state: "TX" },
    delivery: { street: "200 W Washington St", city: "Phoenix", state: "AZ" },
    cargo: {
      pallet_count: 2,
      weight_lb: 520,
      length_in: 48,
      width_in: 40,
      height_in: 48,
      cargo_type: "general_freight",
    },
  },
  {
    id: "05",
    label: "波士顿 MA → 纳什维尔 TN",
    pickup: { street: "1 Congress St", city: "Boston", state: "MA" },
    delivery: { street: "501 Broadway", city: "Nashville", state: "TN" },
    cargo: {
      pallet_count: 2,
      weight_lb: 490,
      length_in: 48,
      width_in: 40,
      height_in: 48,
      cargo_type: "general_freight",
    },
  },
];

function pickRandomPair(): AddressPair {
  const idx = Math.floor(Math.random() * ADDRESS_POOL.length);
  return ADDRESS_POOL[idx]!;
}

function uniqueWeight(base: number): number {
  const nonce = (parseInt(randomUUID().replace(/-/g, ""), 16) % 900) + 1;
  return base + nonce;
}

async function waitForHttpOk(url: string, attempts = 30): Promise<void> {
  for (let i = 0; i < attempts; i += 1) {
    try {
      const res = await fetch(url);
      if (res.ok) {
        return;
      }
    } catch {
      /* retry */
    }
    await new Promise((r) => setTimeout(r, 2000));
  }
  throw new Error(`服务未就绪: ${url}`);
}

function draftAddress(
  draft: Omit<AddressDraft, "zip">,
): QuoteRequestBody["pickup_address"] {
  const street = draft.street.trim();
  const city = draft.city.trim();
  const state = draft.state.trim();
  return {
    street,
    city,
    state,
    zip: "",
    place_id: `draft_${street}_${city}_${state}`.replace(/\s+/g, "_").slice(0, 64),
    formatted_address: `${street}, ${city}, ${state}`,
    selected_from_suggestions: true,
  };
}

async function runOneCase(pair: AddressPair): Promise<{
  ok: boolean;
  quoteId?: string;
  tierCount?: number;
  source?: string;
  error?: string;
}> {
  const userPickup = { ...pair.pickup, zip: "" };
  const userDelivery = { ...pair.delivery, zip: "" };

  const cand = await hostFetchMothershipCandidates(
    BASE,
    TOKEN,
    CUSTOMER_ID,
    userPickup,
    userDelivery,
  );
  if (cand.code !== 0 || !cand.data) {
    return { ok: false, error: cand.message ?? "地址候选失败" };
  }

  const selectedPickup = pickBestMothershipCandidate(
    cand.data.pickup_candidates,
    userPickup,
  );
  const selectedDelivery = pickBestMothershipCandidate(
    cand.data.delivery_candidates,
    userDelivery,
  );
  if (!selectedPickup || !selectedDelivery) {
    return { ok: false, error: "候选为空" };
  }

  const weightLb = uniqueWeight(pair.cargo.weight_lb);
  const body: QuoteRequestBody = {
    request_id: randomUUID(),
    customer_id: CUSTOMER_ID,
    quote_session_id: cand.data.quote_session_id,
    pickup_address: applyMothershipCandidate(
      draftAddress(userPickup),
      selectedPickup,
    ),
    delivery_address: applyMothershipCandidate(
      draftAddress(userDelivery),
      selectedDelivery,
    ),
    weight: { value: weightLb, unit: "lb" },
    dimensions: {
      length: pair.cargo.length_in,
      width: pair.cargo.width_in,
      height: pair.cargo.height_in,
      unit: "in",
    },
    pallet_count: pair.cargo.pallet_count,
    cargo_type: pair.cargo.cargo_type,
  };

  const created = await hostCreateQuote(BASE, TOKEN, body);
  if (created.code !== 0 || !created.data?.quote_id) {
    return { ok: false, error: created.message ?? "创建询价失败" };
  }

  const quoteId = created.data.quote_id;
  let finalDetail = created.data;

  if (finalDetail.status === "processing") {
    const poll = await pollQuoteUntilDone(
      async () => {
        const detail = await hostGetQuote(BASE, TOKEN, CUSTOMER_ID, quoteId);
        if (detail.code !== 0) {
          return { ok: false, errorMessage: detail.message };
        }
        return { ok: true, data: detail.data };
      },
      { timeoutMs: POLL_TIMEOUT_MS },
    );
    if (poll.type !== "done") {
      return {
        ok: false,
        quoteId,
        error: poll.type === "timeout" ? "轮询超时" : poll.message,
      };
    }
    finalDetail = poll.quote;
  }

  const tierCount = finalDetail?.quotes?.length ?? 0;
  const source = finalDetail?.source_type ?? "";
  const ok =
    finalDetail?.status === "done" &&
    tierCount >= 1 &&
    (source === "rpa" || source === "cache");

  return {
    ok,
    quoteId,
    tierCount,
    source: String(source),
    error: ok ? undefined : `status=${finalDetail?.status} tiers=${tierCount} source=${source}`,
  };
}

async function main(): Promise<void> {
  const runId = randomUUID().slice(0, 8);
  await ensureNativeInfraIfNeeded();
  resetRedisClient();
  await ensureRedisReady();
  await waitForHttpOk(`${BASE}/`);

  const workerOk = await isAnyRpaWorkerHealthy();
  if (!workerOk) {
    console.warn("[probe:random] Worker 心跳未就绪，仍尝试运行（可能排队失败）");
  }

  console.log(
    `[probe:random] 开始 ${LOOPS} 次随机地址 widget 报价（dual-address-patch=on）`,
  );

  const results: Array<{
    pairId: string;
    label: string;
    ok: boolean;
    quoteId?: string;
    tierCount?: number;
    source?: string;
    error?: string;
  }> = [];

  let pass = 0;
  let fail = 0;

  for (let i = 0; i < LOOPS; i += 1) {
    const pair = pickRandomPair();
    console.log(`\n[probe:random] case ${i + 1}/${LOOPS}: ${pair.label}`);
    const outcome = await runOneCase(pair);
    results.push({
      pairId: pair.id,
      label: pair.label,
      ...outcome,
    });
    if (outcome.ok) {
      pass += 1;
      console.log(
        `[PASS] ${pair.id} quote=${outcome.quoteId} tiers=${outcome.tierCount} source=${outcome.source}`,
      );
    } else {
      fail += 1;
      console.log(`[FAIL] ${pair.id} ${outcome.error ?? "unknown"}`);
    }
  }

  const report = {
    runId,
    finishedAt: new Date().toISOString(),
    loops: LOOPS,
    pass,
    fail,
    verdict: fail === 0 ? "PASS" : "FAIL",
    env: {
      quoteStrategy: "direct-first-widget-fallback",
      RPA_DUAL_ADDRESS_PATCH: "true",
      RPA_ADDRESS_MODE: "real",
    },
    results,
  };

  const outDir = join(process.cwd(), ".rpa");
  if (!existsSync(outDir)) {
    mkdirSync(outDir, { recursive: true });
  }
  const outPath = join(outDir, `random-address-quote-${runId}.json`);
  writeFileSync(outPath, JSON.stringify(report, null, 2), "utf8");

  console.log(`\n[probe:random] ${pass}/${LOOPS} 通过 | 报告: ${outPath}`);
  process.exit(fail === 0 ? 0 : 1);
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
