import { expect } from "e2e";
import * as Effect from "effect/Effect";
import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
import * as NetService from "@t3tools/shared/Net";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as References from "effect/References";
import { appendFile } from "node:fs/promises";
import * as EnvironmentAuth from "../../apps/server/src/auth/EnvironmentAuth.ts";
import * as ServerConfig from "../../apps/server/src/config.ts";
import { resolveCliAuthConfig } from "../../apps/server/src/cli/config.ts";
import { mcpToolSession } from "../../apps/server/src/mcp/AcpMcpStdioBridge.ts";
import { readPersistedServerRuntimeState } from "../../apps/server/src/serverRuntimeState.ts";
import { T3_HOME } from "../e2e.config.ts";
import { test, WEB, runPromise } from "./t3.ts";

async function call(tool: string, args: Record<string, unknown>) {
  return runPromise(Effect.gen(function* () {
    const config = yield* resolveCliAuthConfig({baseDir: Option.some(T3_HOME)}, Option.none());
    return yield* Effect.gen(function* () {
      const state = yield* readPersistedServerRuntimeState(config.serverRuntimeStatePath);
      if (Option.isNone(state)) throw new Error("Server is not running");
      const auth = yield* EnvironmentAuth.EnvironmentAuth;
      const issued = yield* Effect.acquireRelease(auth.issueMcpClientSession({label:"Evidence driver",access:"full-access",peerLink:false,client:{deviceType:"bot"}}), s => auth.revokeSession(s.sessionId).pipe(Effect.ignore));
      const session = yield* mcpToolSession({endpoint:new URL("/mcp",state.value.origin).href,authorization:`Bearer ${issued.token}`,clientName:"evidence-driver"});
      return yield* session.call(tool,args);
    }).pipe(Effect.scoped,Effect.provide(EnvironmentAuth.layerRuntime.pipe(Layer.provide(ServerConfig.layer(config)),Layer.provide(Layer.succeed(References.MinimumLogLevel,config.logLevel)))));
  }).pipe(Effect.provide([NetService.layer,NodeCrypto.layer])));
}

test("Switching provider instances preserves an active foreground turn", WEB, async ({t3,app,screen,browser}) => {
  await t3.project("provider-switch-demo");
  await t3.open();
  await screen.getByRole("textbox").fill("Run a foreground sleep 90 command and wait for it to finish.");
  await screen.getByRole("textbox").press("Enter");
  // The running tool marks the same active-turn milestone on both commits.
  await screen.getByRole("button","Running sleep",{exact:true}).waitFor({state:"visible"});
  const threadId = await browser.evaluate(() => location.pathname.split("/").at(-1)!);
  const before = await call("t3_thread_configure",{threadId});
  await app.screenshot("active-before-switch");
  const switched = await call("t3_thread_configure",{threadId,modelSelection:{instanceId:"replayB",model:"showcase"}});
  const selection = await call("t3_thread_configure",{threadId});
  const result = await call("t3_thread_wait",{threadId,timeoutMs:120000});
  await app.screenshot("turn-after-switch");
  await appendFile("transcript.ndjson",JSON.stringify({before,switched,selection,result})+"\n");
  await expect(screen.getByText("The original turn finished.",{exact:false})).toBeVisible();
  expect(JSON.stringify(switched)).toContain("Wait for it to finish, then retry");
  expect(JSON.stringify(selection)).toContain("replayA");
  const idle = await call("t3_thread_configure",{threadId,modelSelection:{instanceId:"replayB",model:"showcase"}});
  const idleSelection = await call("t3_thread_configure",{threadId});
  await appendFile("transcript.ndjson",JSON.stringify({idle,idleSelection})+"\n");
  expect(JSON.stringify(idleSelection)).toContain("replayB");
  await app.screenshot("idle-switch-succeeds");
});
