import type { Locator } from "playwright";
import { RPA_STREET_INPUT_CLICK_MS } from "@/lib/constants/rpa";
import { RpaError } from "@/modules/rpa/errors";
import { dismissAddressSuggestionDropdown } from "@/workers/rpa/address-commit";
import { AddressCommitStateMachine } from "@/workers/rpa/address-adapter/commit-state-machine";
import {
  createEmptyDiagnostics,
  logAddressSelectDiagnostics,
} from "@/workers/rpa/address-adapter/diagnostics";
import type {
  AddressAdapter,
  AddressCommitResult,
  AddressSelectDiagnostics,
  SelectAddressParams,
} from "@/workers/rpa/address-adapter/types";

const MOCK_STREET_FILL_MS = Math.min(RPA_STREET_INPUT_CLICK_MS, 5_000);

/** 链路探通：仅 fill 街道文本，不等待 MotherShip 联想/place API */
async function mockTypeStreetInput(
  street: Locator,
  text: string,
): Promise<void> {
  const value = text.replace(/\s+/g, " ").trim().slice(0, 160);
  await street.click({ timeout: MOCK_STREET_FILL_MS }).catch(() => undefined);
  await street.fill("", { timeout: MOCK_STREET_FILL_MS }).catch(() => undefined);
  await street
    .fill(value, { timeout: MOCK_STREET_FILL_MS })
    .catch(() => undefined);
  await street.press("Escape").catch(() => undefined);
  await street.press("Tab").catch(() => undefined);
}

/**
 * mock 模式：快速填入地址文本并合成 commit，不触发 MotherShip place 闸门。
 * 下游 cargo / submit / quote parser 仍真实执行。
 */
export class MockAddressAdapter implements AddressAdapter {
  private readonly stateMachine = new AddressCommitStateMachine();

  private result: AddressCommitResult | null = null;

  private diagnostics: AddressSelectDiagnostics = createEmptyDiagnostics("");

  getCommitState() {
    return this.stateMachine.getState();
  }

  getCommittedAddress(): AddressCommitResult | null {
    return this.result;
  }

  getDiagnostics(): AddressSelectDiagnostics {
    return {
      ...this.diagnostics,
      commitState: this.stateMachine.getState(),
    };
  }

  async selectAddress(params: SelectAddressParams): Promise<AddressCommitResult> {
    const { ctx, side, address, street } = params;
    const page = ctx.page;
    const label =
      address.mothershipDisplayLabel?.trim() ||
      address.formattedAddress?.trim() ||
      address.street;
    const streetText =
      address.formattedAddress?.trim() ||
      `${address.street}, ${address.city ?? ""}, ${address.state ?? ""} ${address.zip ?? ""}`.trim();

    this.diagnostics = createEmptyDiagnostics(label, "EMPTY");
    this.stateMachine.transition("TYPING");
    this.diagnostics.method = "mock-fast-fill";
    this.diagnostics.events.push("mock-mode-start");

    await mockTypeStreetInput(street, streetText);
    await dismissAddressSuggestionDropdown(page, street);
    this.diagnostics.events.push("street-filled");
    this.stateMachine.transition("COMMITTED");

    const placeId =
      address.placeId?.trim() || `mock-place-${side}-${Date.now()}`;
    const formattedAddress = streetText || label;
    this.diagnostics.address = label;
    this.diagnostics.placeId = placeId;
    this.diagnostics.status = "ok";
    this.diagnostics.placeRequestObserved = false;
    this.diagnostics.events.push("mock-commit-synthesized");

    this.result = {
      success: true,
      placeId,
      formattedAddress,
      committed: true,
    };

    logAddressSelectDiagnostics(side, this.getDiagnostics());
    console.log(
      `[rpa] address-mock:${side} 已合成 commit placeId=${placeId}（跳过联想/place API）`,
    );
    return this.result;
  }

  async waitForCommit(): Promise<AddressCommitResult> {
    if (!this.result?.committed) {
      throw new RpaError(
        "ADDRESS_NOT_CONFIRMED",
        "mock waitForCommit：selectAddress 未完成",
        { retryable: false },
      );
    }
    return this.result;
  }
}
