import { randomUUID } from "node:crypto";
import { resolveMothershipCandidates } from "@/modules/address/mothership-candidates";
import type { MothershipAddressCandidate } from "@/modules/address/types";
import { applyHostCandidate } from "@/modules/host/address-mapper";
import {
  deleteHostPublicSession,
  loadHostPublicSession,
  saveHostPublicSession,
} from "@/modules/host/public-session";
import type {
  HostPublicCandidatesResponse,
  HostPublicCargoInput,
  HostPublicAddressDraft,
} from "@/modules/host/types";
import {
  HostQuoteWaitError,
  waitForQuoteDetail,
} from "@/modules/host/wait-for-quote";
import { prisma } from "@/lib/prisma";
import { submitQuote } from "@/modules/quote/orchestrator";
import {
  serializeQuoteDetail,
  type QuoteDetailResponse,
} from "@/modules/quote/quote-serializer";

export class HostPublicError extends Error {
  constructor(
    message: string,
    readonly code: string,
  ) {
    super(message);
    this.name = "HostPublicError";
  }
}

async function loadQuoteDetailOnce(
  quoteId: string,
  customerId: string,
): Promise<QuoteDetailResponse> {
  const record = await prisma.quoteRecord.findFirst({
    where: { quoteId, customerId, isDeleted: false },
  });
  if (!record) {
    throw new HostPublicError("报价不存在", "QUOTE_NOT_FOUND");
  }
  return serializeQuoteDetail(record);
}

function findMatchingCandidate(
  candidates: MothershipAddressCandidate[],
  selected: MothershipAddressCandidate,
  label: string,
): MothershipAddressCandidate {
  if (selected.selectable === false) {
    throw new HostPublicError(
      selected.unavailable_reason ?? `${label}地址不可选`,
      "ADDRESS_NOT_SELECTABLE",
    );
  }

  const matched = candidates.find((c) => c.option_id === selected.option_id);
  if (!matched) {
    throw new HostPublicError(
      `${label}地址不在本次联想结果中，请重新发起联想`,
      "ADDRESS_SESSION_MISMATCH",
    );
  }
  if (matched.selectable === false) {
    throw new HostPublicError(
      matched.unavailable_reason ?? `${label}地址不可选`,
      "ADDRESS_NOT_SELECTABLE",
    );
  }
  return matched;
}

/** 第一步：地址 + 货物 → 联想候选 + host_session_id */
export async function hostPublicResolveCandidates(
  customerId: string,
  input: {
    pickup_address: HostPublicAddressDraft;
    delivery_address: HostPublicAddressDraft;
    cargo: HostPublicCargoInput;
  },
): Promise<HostPublicCandidatesResponse> {
  const pickup = {
    ...input.pickup_address,
    zip: input.pickup_address.zip ?? "",
  };
  const delivery = {
    ...input.delivery_address,
    zip: input.delivery_address.zip ?? "",
  };

  const resolved = await resolveMothershipCandidates({ pickup, delivery });

  const host_session_id = await saveHostPublicSession({
    customer_id: customerId,
    cargo: input.cargo,
    pickup_draft: pickup,
    delivery_draft: delivery,
    quote_session_id: resolved.quote_session_id,
    pickup_candidates: resolved.pickup_candidates,
    delivery_candidates: resolved.delivery_candidates,
  });

  return {
    host_session_id,
    pickup_candidates: resolved.pickup_candidates,
    delivery_candidates: resolved.delivery_candidates,
    requires_selection: resolved.requires_selection,
  };
}

/** 第二步：确认联想地址 → 同步等待 → 返回最终报价 */
export async function hostPublicSubmitAndWait(input: {
  host_session_id: string;
  pickup_candidate: MothershipAddressCandidate;
  delivery_candidate: MothershipAddressCandidate;
}): Promise<QuoteDetailResponse> {
  const session = await loadHostPublicSession(input.host_session_id);
  if (!session) {
    throw new HostPublicError("会话已过期，请重新发起联想", "SESSION_EXPIRED");
  }

  const pickup = findMatchingCandidate(
    session.pickup_candidates,
    input.pickup_candidate,
    "提货",
  );
  const delivery = findMatchingCandidate(
    session.delivery_candidates,
    input.delivery_candidate,
    "派送",
  );

  const body = {
    request_id: randomUUID(),
    customer_id: session.customer_id,
    quote_session_id: session.quote_session_id,
    pickup_address: applyHostCandidate(session.pickup_draft, pickup),
    delivery_address: applyHostCandidate(session.delivery_draft, delivery),
    weight: session.cargo.weight,
    dimensions: session.cargo.dimensions,
    pallet_count: session.cargo.pallet_count,
    cargo_type: session.cargo.cargo_type,
  };

  const created = await submitQuote(body);
  if (!created.quote_id) {
    throw new HostPublicError("创建询价失败", "QUOTE_CREATE_FAILED");
  }

  try {
    if (created.status === "done") {
      return await loadQuoteDetailOnce(created.quote_id, session.customer_id);
    }
    return await waitForQuoteDetail(created.quote_id, session.customer_id);
  } finally {
    await deleteHostPublicSession(input.host_session_id);
  }
}

export { HostQuoteWaitError };
