import { registerPlugin } from "@capacitor/core";
import { createCapacitorHttpTransport } from "../../android/capacitorHttpTransport.js";
import { createEngine } from "../../src/engine.js";
import { ChallengeRequiredError } from "../../src/core/browserErrors.js";
import { MemoryResponseCache } from "../../src/core/memoryCache.js";
import { PoliteCore } from "../../src/core/politeCore.js";
import type { BrowserFetcher, StoreSearchResponse } from "../../src/core/types.js";
import { phaseFVerdict } from "./verdict.js";

interface NativePageResult {
  storeId: string;
  url: string;
  status: number;
  body: string;
  challenged: boolean;
  cookieCount: number;
}

interface WebViewFetcherPlugin {
  fetchPageHtml(options: { storeId: string; url: string; timeoutMs?: number }): Promise<NativePageResult>;
  show(options: { storeId: string }): Promise<void>;
}

const NativeWebView = registerPlugin<WebViewFetcherPlugin>("WebViewFetcher");

const transport = createCapacitorHttpTransport();

const browser: BrowserFetcher = {
  async fetchPageHtml(storeId, url) {
    const page = await NativeWebView.fetchPageHtml({ storeId, url, timeoutMs: 45_000 });
    if (page.challenged) throw new ChallengeRequiredError(storeId, `android://solve/${storeId}`);
    return page.body;
  },
  async fetchJson(storeId, homepage, url) {
    void homepage;
    return this.fetchPageHtml(storeId, url);
  },
  async fetchOriginHtml(storeId, homepage, url) {
    void homepage;
    return this.fetchPageHtml(storeId, url);
  },
};

const engine = createEngine({
  http: new PoliteCore({ transport }),
  browser,
  cache: new MemoryResponseCache(-1),
});

const openStoreIds = ["partsale", "xparts", "eoltas", "carparts", "handler"];
const query = "W71252";
const report = {
  phase: "F",
  runtime: "Capacitor Android",
  query,
  startedAt: new Date().toISOString(),
  openStores: [] as StoreSearchResponse[],
  autodoc: [] as StoreSearchResponse[],
};

const summary = required("summary");
const results = required("results");
const reportElement = required("report");
const showSolve = requiredButton("show-solve");
requiredButton("run-open").addEventListener("click", () => void runOpenStores());
requiredButton("run-walled").addEventListener("click", () => void runAutodoc());
showSolve.addEventListener("click", () => void showChallenge());

void runAll().catch(fatalError);

async function runAll(): Promise<void> {
  await runOpenStores();
  await runAutodoc();
}

function fatalError(error: unknown): void {
  document.body.dataset.state = "failed";
  summary.textContent = `Harness failure: ${error instanceof Error ? error.message : String(error)}`;
  reportElement.textContent = JSON.stringify(report, null, 2);
  console.error("PHASE_F_FATAL", error);
  setBusy(false);
}

async function runOpenStores(): Promise<void> {
  setBusy(true, "Running five open stores through native HTTP…");
  report.openStores = await Promise.all(openStoreIds.map((storeId) => engine.search(storeId, query)));
  for (const outcome of report.openStores) renderOutcome(outcome, "CapacitorHttp");
  finishState();
}

async function runAutodoc(): Promise<void> {
  setBusy(true, "Running Autodoc in a persistent native WebView…");
  report.autodoc = [];
  report.autodoc.push(await engine.search("autodoc", query));
  if (report.autodoc[0]?.ok) report.autodoc.push(await engine.search("autodoc", query));
  for (const outcome of report.autodoc) renderOutcome(outcome, "WebViewFetcher");
  showSolve.hidden = !report.autodoc.some((outcome) => outcome.needsSolve);
  finishState();
}

async function showChallenge(): Promise<void> {
  await NativeWebView.show({ storeId: "autodoc" });
  showSolve.hidden = true;
  await runAutodoc();
}

function finishState(): void {
  const verdict = phaseFVerdict(report.openStores, report.autodoc, openStoreIds.length);
  document.body.dataset.state = verdict.state;
  summary.textContent = verdict.summary;
  reportElement.textContent = JSON.stringify(report, null, 2);
  console.log(`PHASE_F_RESULT ${JSON.stringify({ state: verdict.state, report })}`);
  setBusy(false);
}

function isUsefulResult(outcome: StoreSearchResponse): boolean {
  return outcome.ok && outcome.offers.length > 0;
}

function renderOutcome(outcome: StoreSearchResponse, transportName: string): void {
  const card = document.createElement("div");
  const passed = isUsefulResult(outcome);
  card.className = `card ${passed ? "pass" : "fail"}`;
  card.textContent = `${passed ? "PASS" : outcome.needsSolve ? "SOLVE" : "FAIL"} · ${outcome.displayName} · ${outcome.offers.length} offers · ${outcome.durationMs} ms · ${transportName}`;
  results.append(card);
}

function setBusy(busy: boolean, message?: string): void {
  for (const button of document.querySelectorAll<HTMLButtonElement>("button")) button.disabled = busy;
  if (message) summary.textContent = message;
}

function required(id: string): HTMLElement {
  const element = document.getElementById(id);
  if (!element) throw new Error(`missing #${id}`);
  return element;
}

function requiredButton(id: string): HTMLButtonElement {
  return required(id) as HTMLButtonElement;
}
