import { randomUUID } from "node:crypto";
import {
  SESSION_CONFIRM_POLL_MS,
  SESSION_CONFIRM_RESULT_PREFIX,
  SESSION_CONFIRM_RESULT_TTL_SECONDS,
  SESSION_CONFIRM_TIMEOUT_MS,
} from "@/lib/constants/session-confirm-queue";
import { ensureNativeInfraIfNeeded } from "@/lib/infra/ensure-native-infra";
import {
  ensureRedisReady,
  getRedis,
  resetRedisClient,
} from "@/lib/redis";
import { isAnyRpaWorkerHealthy } from "@/lib/rpa/worker-health";
import type { MothershipAddressCandidate } from "@/modules/address/types";
import type { SessionConfirmJobData } from "@/modules/address/session-confirm-queue-types";
import { RpaError } from "@/modules/rpa/errors";
import { addSessionConfirmJob } from "@/workers/rpa/queue";

type StoredConfirmResult =
  | { ok: true }
  | { ok: false; code: string; message: string; retryable?: boolean };

function resultKey(jobId: string): string {
  return `${SESSION_CONFIRM_RESULT_PREFIX}${jobId}`;
}

async function ensureConfirmRedisReady(): Promise<void> {
  try {
    await ensureRedisReady(10, 800);
  } catch {
    ensureNativeInfraIfNeeded();
    resetRedisClient();
    await ensureRedisReady(15, 1_000);
  }
}

export async function saveSessionConfirmResult(
  jobId: string,
  payload: StoredConfirmResult,
): Promise<void> {
  await ensureConfirmRedisReady();
  await getRedis().setex(
    resultKey(jobId),
    SESSION_CONFIRM_RESULT_TTL_SECONDS,
    JSON.stringify(payload),
  );
}

/** 用户确认 MotherShip 地址后，在同驻留页锁定双地址 */
export async function requestSessionAddressConfirm(input: {
  sessionId: string;
  pickup: MothershipAddressCandidate;
  delivery: MothershipAddressCandidate;
}): Promise<void> {
  if (process.env.RPA_QUEUE_ENABLED === "false") {
    throw new RpaError(
      "PAGE_LOAD_TIMEOUT",
      "RPA 队列已禁用，无法在同页确认地址",
      { retryable: false },
    );
  }

  const workerOk = await isAnyRpaWorkerHealthy().catch(() => false);
  if (!workerOk) {
    throw new RpaError(
      "PAGE_LOAD_TIMEOUT",
      "RPA Worker 未运行，无法复用驻留页（请 npm run worker:rpa）",
      { retryable: true },
    );
  }

  await ensureConfirmRedisReady();
  const jobId = randomUUID();
  const payload: SessionConfirmJobData = {
    jobId,
    sessionId: input.sessionId,
    pickup: input.pickup,
    delivery: input.delivery,
  };
  await addSessionConfirmJob(payload);

  const deadline = Date.now() + SESSION_CONFIRM_TIMEOUT_MS;
  while (Date.now() < deadline) {
    const raw = await getRedis().get(resultKey(jobId));
    if (raw) {
      const stored = JSON.parse(raw) as StoredConfirmResult;
      if (stored.ok) {
        return;
      }
      throw new RpaError(
        stored.code as "PAGE_LOAD_TIMEOUT",
        stored.message,
        { retryable: stored.retryable ?? false },
      );
    }
    await new Promise((resolve) => setTimeout(resolve, SESSION_CONFIRM_POLL_MS));
  }

  throw new RpaError(
    "PAGE_LOAD_TIMEOUT",
    "地址确认超时，请重新获取候选",
    { retryable: true },
  );
}
