import { logger as P, errorLogPath as $ } from "@php-wasm/logger";
import { createNodeFsMountHandler as _, loadNodeRuntime as v } from "@php-wasm/node";
import { EmscriptenDownloadMonitor as x } from "@php-wasm/progress";
import { exposeAPI as W, PHPWorker as S, consumeAPI as k, consumeAPISync as M, PHPResponse as R, PHPExecutionFailureError as H, sandboxedSpawnHandlerFactory as A } from "@php-wasm/universal";
import { phpVar as y, sprintf as B } from "@php-wasm/util";
import { bootRequestHandler as E } from "@wp-playground/wordpress";
import { existsSync as T } from "fs";
import w from "path";
import { rootCertificates as F } from "tls";
import { MessageChannel as O, parentPort as j } from "worker_threads";
import { jspi as C } from "wasm-feature-detect";
async function L() {
  let t = null;
  const e = (await import("./blueprints-BQYAZ9gc.js")).default;
  if (typeof process < "u" && process.versions?.node) {
    let s = e;
    s.startsWith("/@fs/") && (s = s.slice(4)), s.startsWith("file://") && (s = s.slice(7));
    const { readFile: o } = await import("node:fs/promises");
    t = await o(s);
  } else
    t = await (await fetch(e)).blob();
  return new File([t], "blueprints.phar", {
    type: "application/zip"
  });
}
function q(t) {
  if (typeof t == "object" && "type" in t && ["inline-file", "file-reference"].includes(t.type))
    return t;
  if (!t)
    return {
      type: "inline-file",
      contents: "{}"
    };
  if (typeof t != "string")
    return {
      type: "inline-file",
      contents: JSON.stringify(t)
    };
  try {
    return JSON.parse(t), {
      type: "inline-file",
      contents: t
    };
  } catch {
    return {
      type: "file-reference",
      reference: t
    };
  }
}
async function D(t) {
  const e = t.cliArgs || [];
  for (const i of e)
    if (i.startsWith("--site-path="))
      throw new Error(
        "The --site-path CLI argument must not be provided. In Playground, it is always set to /wordpress."
      );
  e.push("--site-path=/wordpress"), e.find((i) => i.startsWith("--db-engine=")) || e.push("--db-engine=sqlite");
  const o = t.php, u = t?.onMessage || (() => {
  }), f = await L();
  o.writeFile(
    "/tmp/blueprints.phar",
    new Uint8Array(await f.arrayBuffer())
  );
  const c = q(
    t.blueprint
  );
  let n = "";
  switch (c.type) {
    case "inline-file":
      o.writeFile(
        "/tmp/blueprint.json",
        c.contents
      ), n = "/tmp/blueprint.json";
      break;
    case "file-reference":
      n = c.reference;
      break;
  }
  const l = await o.onMessage(async (i) => {
    try {
      const r = typeof i == "string" ? JSON.parse(i) : i;
      if (!r)
        return;
      await new Promise((d) => setTimeout(d, 0)), r.type.startsWith("blueprint.") && await u(r);
    } catch (r) {
      P.warn("Failed to parse message as JSON:", i, r);
    }
  });
  await o?.writeFile(
    "/tmp/run-blueprints.php",
    `<?php
function playground_http_client_factory() {
	return new WordPress\\HttpClient\\Client([
		// sockets transport is somehow faster than curl in Playground. Maybe
		// it uses a larger chunk size?
		'transport' => 'sockets',
	]);
}
playground_add_filter('blueprint.http_client', 'playground_http_client_factory');

function playground_on_blueprint_target_resolved() {
	post_message_to_js(json_encode([
		'type' => 'blueprint.target_resolved',
	]));
}
playground_add_filter('blueprint.target_resolved', 'playground_on_blueprint_target_resolved');

playground_add_filter('blueprint.resolved', 'playground_on_blueprint_resolved');
function playground_on_blueprint_resolved($blueprint) {
	$additional_blueprint_steps = json_decode(${y(
      JSON.stringify(t.blueprintOverrides?.additionalSteps || [])
    )}, true);
	if(count($additional_blueprint_steps) > 0) {
		$blueprint['additionalStepsAfterExecution'] = array_merge(
			$blueprint['additionalStepsAfterExecution'] ?? [],
			$additional_blueprint_steps
		);
	}

	$wp_version_override = json_decode(${y(
      JSON.stringify(t.blueprintOverrides?.wordpressVersion || null)
    )}, true);
	if($wp_version_override) {
		$blueprint['wordpressVersion'] = $wp_version_override;
	}
	return $blueprint;
}

function playground_progress_reporter() {
	class PlaygroundProgressReporter implements ProgressReporter {

		public function reportProgress(float $progress, string $caption): void {
			$this->writeJsonMessage([
				'type' => 'blueprint.progress',
				'progress' => round($progress, 2),
				'caption' => $caption
			]);
		}

		public function reportError(string $message, ?Throwable $exception = null): void {
			$errorData = [
				'type' => 'blueprint.error',
				'message' => $message
			];

			if ($exception) {
				$errorData['details'] = [
					'exception' => get_class($exception),
					'message' => $exception->getMessage(),
					'file' => $exception->getFile(),
					'line' => $exception->getLine(),
					'trace' => $exception->getTraceAsString()
				];
			}

			$this->writeJsonMessage($errorData);
		}

		public function reportCompletion(string $message): void {
			$this->writeJsonMessage([
				'type' => 'blueprint.completion',
				'message' => $message
			]);
		}

		public function close(): void {}

		private function writeJsonMessage(array $data): void {
			post_message_to_js(json_encode($data));
		}
	}
	return new PlaygroundProgressReporter();
}
playground_add_filter('blueprint.progress_reporter', 'playground_progress_reporter');
require( "/tmp/blueprints.phar" );
`
  );
  const a = await o.cli([
    "/internal/shared/bin/php",
    "/tmp/run-blueprints.php",
    "exec",
    n,
    ...e
  ]);
  return a.finished.finally(l), a;
}
async function h(t, e) {
  for (const s of e)
    try {
      t.mkdir(s.vfsPath), await t.mount(
        s.vfsPath,
        _(s.hostPath)
      );
    } catch {
      p.stderr(
        `\x1B[31m\x1B[1mError mounting path ${s.hostPath} at ${s.vfsPath}\x1B[0m
`
      ), process.exit(1);
    }
}
function I(t, e, ...s) {
  console.log(
    performance.now().toFixed(6).padStart(15, "0"),
    t.toString().padStart(16, "0"),
    B(e, ...s)
  );
}
Object.defineProperty(process.stdout, "isTTY", { value: !0 });
Object.defineProperty(process.stderr, "isTTY", { value: !0 });
const p = {
  lastWriteWasProgress: !1,
  progress(t) {
    process.stdout.isTTY ? (p.lastWriteWasProgress || process.stdout.write(`
`), process.stdout.write("\r\x1B[K" + t), p.lastWriteWasProgress = !0) : console.log(t);
  },
  stdout(t) {
    p.lastWriteWasProgress && (process.stdout.write(`
`), p.lastWriteWasProgress = !1), process.stdout.write(t);
  },
  stderr(t) {
    p.lastWriteWasProgress && (process.stdout.write(`
`), p.lastWriteWasProgress = !1), process.stderr.write(t);
  }
};
class J extends S {
  constructor(e) {
    super(void 0, e), this.booted = !1;
  }
  /**
   * Call this method before boot() to use file locking.
   *
   * This method is separate from boot() to simplify the related Comlink.transferHandlers
   * setup – if an argument is a MessagePort, we're transferring it, not copying it.
   *
   * @see comlink-sync.ts
   * @see phpwasm-emscripten-library-file-locking-for-node.js
   */
  async useFileLockManager(e) {
    await C() ? this.fileLockManager = k(e) : this.fileLockManager = await M(e);
  }
  async bootAsPrimaryWorker(e) {
    await this.bootRequestHandler(e);
    const s = this.__internal_getPHP();
    if (await h(s, e["mount-before-install"] || []), e.mode === "mount-only") {
      await h(s, e.mount || []);
      return;
    }
    await this.runBlueprintV2(e);
  }
  async bootAsSecondaryWorker(e) {
    await this.bootRequestHandler(e);
    const s = this.__internal_getPHP();
    await h(s, e["mount-before-install"] || []), await h(s, e.mount || []);
  }
  async runBlueprintV2(e) {
    const s = this.__internal_getRequestHandler(), { php: o, reap: u } = await s.processManager.acquirePHPInstance({
      considerPrimary: !1
    }), f = this.__internal_getPHP();
    let c = () => {
    };
    if (typeof e.blueprint == "string") {
      const n = w.resolve(process.cwd(), e.blueprint);
      T(n) && (f.mkdir("/internal/shared/cwd"), c = await f.mount(
        "/internal/shared/cwd",
        _(w.dirname(n))
      ), e.blueprint = w.join(
        "/internal/shared/cwd",
        w.basename(e.blueprint)
      ));
    }
    try {
      const l = [
        "mode",
        "db-engine",
        "db-host",
        "db-user",
        "db-pass",
        "db-name",
        "db-path",
        "truncate-new-site-directory",
        "allow"
      ].filter((r) => r in e).map((r) => `--${r}=${e[r]}`);
      l.push(`--site-url=${e.siteUrl}`);
      let a = !1;
      const i = await D({
        php: o,
        blueprint: e.blueprint,
        blueprintOverrides: {
          additionalSteps: e["additional-blueprint-steps"],
          wordpressVersion: e.wp
        },
        cliArgs: l,
        onMessage: async (r) => {
          switch (r.type) {
            case "blueprint.target_resolved": {
              a || (await h(
                f,
                e.mount || []
              ), a = !0);
              break;
            }
            case "blueprint.progress": {
              const d = `${r.caption.trim()} – ${r.progress.toFixed(
                2
              )}%`;
              p.progress(d);
              break;
            }
            case "blueprint.error": {
              const d = "\x1B[31m", g = "\x1B[1m", m = "\x1B[0m";
              e.debug && r.details ? p.stderr(
                `${d}${g}Fatal error:${m} Uncaught ${r.details.exception}: ${r.details.message}
  at ${r.details.file}:${r.details.line}
` + (r.details.trace ? r.details.trace + `
` : "")
              ) : p.stderr(
                `${d}${g}Error:${m} ${r.message}
`
              );
              break;
            }
          }
        }
      });
      if (e.debug && (i.stdout.pipeTo(
        new WritableStream({
          write(r) {
            process.stdout.write(r);
          }
        })
      ), i.stderr.pipeTo(
        new WritableStream({
          write(r) {
            process.stderr.write(r);
          }
        })
      )), await i.finished, await i.exitCode !== 0) {
        const r = await R.fromStreamedResponse(
          i
        );
        throw new H(
          `PHP.run() failed with exit code ${r.exitCode}.`,
          r,
          "request"
        );
      }
    } catch (n) {
      let l = "";
      try {
        l = o.readFileAsText($);
      } catch {
      }
      throw n.phpLogs = l, n;
    } finally {
      u(), c();
    }
  }
  async bootRequestHandler({
    siteUrl: e,
    allow: s,
    php: o,
    firstProcessId: u,
    processIdSpaceLength: f,
    trace: c
  }) {
    if (this.booted)
      throw new Error("Playground already booted");
    this.booted = !0;
    let n = u;
    const l = u + f - 1;
    try {
      const a = {
        WP_DEBUG: !0,
        WP_DEBUG_LOG: !0,
        WP_DEBUG_DISPLAY: !1
      }, i = await E({
        siteUrl: e,
        createPhpRuntime: async () => {
          const d = n;
          return n < l ? n++ : n = u, await v(o, {
            emscriptenOptions: {
              fileLockManager: this.fileLockManager,
              processId: d,
              trace: c ? I : void 0,
              ENV: {
                DOCROOT: "/wordpress"
              }
            },
            followSymlinks: s?.includes("follow-symlinks")
          });
        },
        sapiName: "cli",
        createFiles: {
          "/internal/shared/ca-bundle.crt": F.join(`
`)
        },
        constants: a,
        phpIniEntries: {
          "openssl.cafile": "/internal/shared/ca-bundle.crt"
        },
        cookieStore: !1,
        spawnHandler: A
      });
      this.__internal_setRequestHandler(i);
      const r = await i.getPrimaryPhp();
      await this.setPrimaryPHP(r), N();
    } catch (a) {
      throw V(a), a;
    }
  }
  // Provide a named disposal method that can be invoked via comlink.
  async dispose() {
    await this[Symbol.asyncDispose]();
  }
}
const b = new O(), [N, V] = W(
  new J(new x()),
  void 0,
  b.port1
);
j.postMessage(
  {
    command: "worker-script-initialized",
    phpPort: b.port2
  },
  [b.port2]
);
export {
  J as PlaygroundCliBlueprintV2Worker
};
//# sourceMappingURL=worker-thread-v2.js.map
