/**
 * 逆向工程 R1-R7：Google Places Autocomplete 可行性探测
 */
import "dotenv/config";
import { mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { loadDevEnv } from "@/lib/dev-env";
import { openAddressSide, visibleStreetInput } from "@/workers/rpa/address-side";
import { ensureAddressSuggestions } from "@/workers/rpa/address-suggestions";
import { RPAContext } from "@/workers/rpa/kernel/context";
import {
  AUTOCOMPLETE_MONKEY_PATCH_INIT,
  buildVerdict,
} from "@/workers/rpa/fix-place/recon-helpers";
import { closeBrowser, openQuotePage } from "@/workers/rpa/session-manager";
import { quotePageAdapter } from "@/workers/rpa/quote-page-adapter";
import {
  stabilizeQuoteLandingPage,
  waitForQuoterWidgetHydrated,
} from "@/workers/rpa/page-prep";

loadDevEnv();

const OUT_DIR = join(process.cwd(), ".rpa", "recon");

declare global {
  interface Window {
    __rpaAutocompleteInstances?: Array<{
      getPlace: () => unknown;
    }>;
    __rpaAutocompletePatched?: boolean;
  }
}

function runReconProbeInBrowser() {
  try {
    const result = {
      googleMapsLoaded:
        typeof google !== "undefined" && typeof google.maps !== "undefined",
      triggerAvailable: typeof google?.maps?.event?.trigger === "function",
      placesLoaded:
        typeof google?.maps?.places?.Autocomplete === "function",
      globalAutocompleteVars: [] as string[],
      inputProbes: [] as Array<{
        index: number;
        gmKeys: number;
        pacTarget: boolean;
        placeholder: string;
      }>,
      pacTargetInputSelector: "",
      autocompleteAccessPath: "not-found",
      autocompleteInstanceFound: false,
      reactFiberKey: "not-found",
      widgetComponentName: "unknown",
      widgetStateStructure: {} as Record<string, unknown>,
      cspRestrictions: "none",
      placeChangedTriggerOk: false,
    };

    if (result.googleMapsLoaded) {
      result.globalAutocompleteVars = Object.keys(window).filter((k) => {
        try {
          return window[k] instanceof google.maps.places.Autocomplete;
        } catch {
          return false;
        }
      });
    }

    const widget = document.querySelector("#react-quoter-landing-plugin");
    if (widget) {
      const fiberKey = Object.keys(widget).find(
        (k) =>
          k.startsWith("__reactFiber$") ||
          k.startsWith("__reactInternalInstance$"),
      );
      if (fiberKey) {
        result.reactFiberKey = fiberKey;
        let fiber = (widget as Record<string, unknown>)[fiberKey] as {
          stateNode?: { state?: Record<string, unknown> };
          type?: { name?: string; displayName?: string };
          return?: unknown;
        };
        while (fiber) {
          if (fiber.stateNode?.state) {
            const stateKeys = Object.keys(fiber.stateNode.state);
            if (stateKeys.some((k) => /pickup|delivery|address/i.test(k))) {
              result.widgetComponentName =
                fiber.type?.name || fiber.type?.displayName || "unknown";
              result.widgetStateStructure = Object.fromEntries(
                stateKeys
                  .filter((k) => /pickup|delivery|address/i.test(k))
                  .map((k) => [k, typeof fiber.stateNode!.state![k]]),
              );
            }
          }
          fiber = fiber.return as typeof fiber;
        }
      }
    }

    const inputs = widget
      ? Array.from(widget.querySelectorAll('input[type="text"]'))
      : Array.from(document.querySelectorAll('input[type="text"]'));

    for (let i = 0; i < inputs.length; i += 1) {
      const input = inputs[i]!;
      const gm = Object.keys(input).filter((k) => k.startsWith("gm_"));
      const pac = input.classList.contains("pac-target-input");
      result.inputProbes.push({
        index: i,
        gmKeys: gm.length,
        pacTarget: pac,
        placeholder: (input as HTMLInputElement).placeholder || "",
      });
      if (pac && !result.pacTargetInputSelector) {
        result.pacTargetInputSelector = ".pac-target-input";
      }
    }

    if (!result.pacTargetInputSelector && inputs.length > 0) {
      result.pacTargetInputSelector = "#react-quoter-landing-plugin input";
    }

    const resolveInstance = () => {
      const instances = window.__rpaAutocompleteInstances ?? [];
      if (instances.length > 0) {
        result.autocompleteAccessPath = "window.__rpaAutocompleteInstances";
        return instances[instances.length - 1] ?? null;
      }
      if (result.globalAutocompleteVars.length > 0) {
        result.autocompleteAccessPath = `window.${result.globalAutocompleteVars[0]}`;
        return window[result.globalAutocompleteVars[0]!] as {
          getPlace: () => unknown;
        };
      }
      const pacInput =
        document.querySelector(".pac-target-input") ||
        document.querySelector("#react-quoter-landing-plugin input");
      if (!pacInput) {
        return null;
      }
      for (const key of Object.keys(pacInput)) {
        if (!key.startsWith("gm_")) {
          continue;
        }
        const val = (pacInput as Record<string, unknown>)[key];
        if (
          val &&
          typeof val === "object" &&
          typeof (val as { getPlace?: unknown }).getPlace === "function"
        ) {
          result.autocompleteAccessPath = "input[gm_*].getPlace";
          return val as { getPlace: () => unknown };
        }
      }
      return null;
    };

    const instance = resolveInstance();
    result.autocompleteInstanceFound = Boolean(instance);

    const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
    result.cspRestrictions = meta?.getAttribute("content") ?? "none";

    if (
      instance &&
      result.triggerAvailable &&
      typeof instance.getPlace === "function"
    ) {
      try {
        const originalGetPlace = instance.getPlace.bind(instance);
        instance.getPlace = () => ({
          place_id: "ChIJReconProbePlaceId0000000",
          formatted_address: "1234 Recon Probe St, Los Angeles, CA",
          name: "1234 Recon Probe St",
          geometry: { location: { lat: () => 34.05, lng: () => -118.25 } },
        });
        google.maps.event.trigger(instance, "place_changed");
        result.placeChangedTriggerOk = true;
        setTimeout(() => {
          instance.getPlace = originalGetPlace;
        }, 50);
      } catch {
        result.placeChangedTriggerOk = false;
      }
    }

    return result;
  } catch (error) {
    return {
      googleMapsLoaded: false,
      triggerAvailable: false,
      placesLoaded: false,
      globalAutocompleteVars: [],
      inputProbes: [],
      pacTargetInputSelector: "",
      autocompleteAccessPath: "not-found",
      autocompleteInstanceFound: false,
      reactFiberKey: "not-found",
      widgetComponentName: "unknown",
      widgetStateStructure: {},
      cspRestrictions: "none",
      placeChangedTriggerOk: false,
      probeError: String(error),
    };
  }
}

async function main(): Promise<void> {
  process.env.RPA_HEADLESS = "false";
  process.env.RPA_ADDRESS_MODE = "real";
  process.env.RPA_MOCK_MODE = "false";

  mkdirSync(OUT_DIR, { recursive: true });

  const opened = await openQuotePage(quotePageAdapter, false, undefined, {
    freshCargoContext: true,
  });
  const { page, context } = opened;

  await context.addInitScript(AUTOCOMPLETE_MONKEY_PATCH_INIT);
  await page.reload({ waitUntil: "domcontentloaded" });

  const rpaCtx = RPAContext.fromSession(page, context);
  await stabilizeQuoteLandingPage(rpaCtx);
  await waitForQuoterWidgetHydrated(page);

  await openAddressSide(rpaCtx, "pickup");
  const street = await visibleStreetInput(rpaCtx, "pickup", {
    deliverySectionOpened: false,
  });
  if (!street) {
    throw new Error("recon: pickup street input not found");
  }

  const queryHint = {
    street: "1234 Warehouse Street",
    city: "Los Angeles",
    state: "CA",
    zip: "",
  };
  await ensureAddressSuggestions(page, street, queryHint, {
    mothershipLabel: "1234 Warehouse Street, Los Angeles, CA",
  });

  await page.waitForTimeout(1500);

  const probe = await page.evaluate(runReconProbeInBrowser);
  const verdict = buildVerdict(probe);

  const outPath = join(OUT_DIR, "verdict.json");
  writeFileSync(outPath, JSON.stringify(verdict, null, 2), "utf8");

  console.log("[recon] verdict:", verdict.verdict);
  console.log("[recon] googleMapsLoaded:", verdict.googleMapsLoaded);
  console.log("[recon] autocompleteAccessPath:", verdict.autocompleteAccessPath);
  console.log("[recon] placeChangedTriggerOk:", verdict.placeChangedTriggerOk);
  console.log("[recon] written:", outPath);

  await closeBrowser();
}

main().catch(async (error) => {
  console.error("[recon] failed:", error);
  await closeBrowser().catch(() => undefined);
  process.exit(1);
});
