import * as SourceControlProviderRegistry from "../sourceControl/SourceControlProviderRegistry.ts";
import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";
import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
import * as NodeServices from "@effect/platform-node/NodeServices";
import assert from "node:assert/strict";
import fs from "node:fs";
import {
  CheckpointId,
  CommandId,
  EventId,
  MessageId,
  type ModelSelection,
  NodeId,
  type OrchestrationV2Run,
  ProjectId,
  ProviderDriverKind,
  ProviderInstanceId,
  ProviderThreadId,
  RunId,
  RuntimeRequestId,
  ThreadId,
  TurnItemId,
} from "@t3tools/contracts";
import * as DateTime from "effect/DateTime";
import * as Effect from "effect/Effect";
import * as Deferred from "effect/Deferred";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import * as Stream from "effect/Stream";
import * as Tracer from "effect/Tracer";
import * as TestClock from "effect/testing/TestClock";

import * as CheckpointStore from "../checkpointing/CheckpointStore.ts";
import * as ServerConfig from "../config.ts";
import * as McpSessionRegistryTestkit from "../mcp/McpSessionRegistry.testkit.ts";
import * as SqlitePersistence from "../persistence/Sqlite.ts";
import * as ProjectEnrichmentService from "../project/ProjectEnrichmentService.ts";
import * as ProjectService from "../project/ProjectService.ts";
import type { ProviderInstance } from "@t3tools/provider-core/server/driver";
import * as ProviderInstanceRegistry from "../provider/ProviderInstanceRegistry.ts";
import * as ServerSettings from "../serverSettings.ts";
import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts";
import * as VcsProcess from "../vcs/VcsProcess.ts";
import * as WorkspacePaths from "../workspace/WorkspacePaths.ts";
import { CodexProviderCapabilitiesV2 } from "./Adapters/CodexAdapterV2.ts";
import * as EventSink from "./EventSink.ts";
import * as Orchestrator from "./Orchestrator.ts";
import { continueRestartedRun } from "./RestartContinuation.ts";
import * as RuntimeLayer from "./runtimeLayer.ts";
import * as ThreadCommandExecutor from "./ThreadCommandExecutor.ts";
import { limitRecoveryCommand } from "./UsageLimitRecoveryWorker.ts";
import * as ProviderTurnStartServiceTestkit from "./ProviderTurnStartService.testkit.ts";
import type * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";
import * as ProviderContinuationRequests from "@t3tools/provider-core/server/ProviderContinuationRequests";
import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";
import * as ProviderContinuationService from "./ProviderContinuationService.ts";

const layerPlatformTest = Layer.merge(
  Layer.mergeAll(NodeServices.layer, NodeCrypto.layer),
  Layer.mock(SourceControlProviderRegistry.SourceControlProviderRegistry)({
    resolveLink: () => Effect.die("unused title link"),
  }),
);

const layerServerConfig = ServerConfig.layerTest(process.cwd(), {
  prefix: "t3-orchestration-v2-delegated-completion-",
});

const modelSelection = {
  instanceId: ProviderInstanceId.make("codex"),
  model: "synthetic-harness-scenario",
} satisfies ModelSelection;

const layerVcsDriverRegistryTest = VcsDriverRegistry.layer.pipe(
  Layer.provide(VcsProcess.layer),
  Layer.provide(layerServerConfig),
  Layer.provide(layerPlatformTest),
);

const layerCheckpointStoreTest = CheckpointStore.layer.pipe(
  Layer.provide(layerVcsDriverRegistryTest),
);

const driver = ProviderDriverKind.make("codex");
const orchestrationAdapter = {
  instanceId: modelSelection.instanceId,
  driver,
  getCapabilities: () => Effect.succeed(CodexProviderCapabilitiesV2),
  planSelectionTransition: () => Effect.succeed({ type: "apply_on_next_turn" }),
  openSession: () => Effect.die("sessions are not used by delegated completion tests"),
} as ProviderAdapter.ProviderAdapterV2["Service"];
const providerInstance = {
  instanceId: modelSelection.instanceId,
  driverKind: driver,
  continuationIdentity: {
    driverKind: driver,
    continuationKey: "codex:test",
  },
  displayName: "Codex test",
  enabled: true,
  snapshot: { getSnapshot: Effect.succeed({}) } as unknown as ProviderInstance["snapshot"],
  orchestrationAdapter,
  textGeneration: {} as ProviderInstance["textGeneration"],
} satisfies ProviderInstance;

const layerTestProviderInstanceRegistry = Layer.succeed(
  ProviderInstanceRegistry.ProviderInstanceRegistry,
  {
    getInstance: (instanceId) =>
      Effect.succeed(instanceId === providerInstance.instanceId ? providerInstance : undefined),
    listInstances: Effect.succeed([providerInstance]),
    listUnavailable: Effect.succeed([]),
    streamChanges: Stream.empty,
    subscribeChanges: Effect.never,
  },
);

const layerTest = Layer.mergeAll(
  RuntimeLayer.layer,
  RuntimeLayer.layerEventSink,
  ThreadCommandExecutor.layer,
).pipe(
  Layer.provideMerge(RuntimeLayer.layerProjectService),
  Layer.provide(
    Layer.mock(WorkspacePaths.WorkspacePaths)({
      normalizeWorkspaceRoot: (workspaceRoot) => Effect.succeed(workspaceRoot),
    }),
  ),
  Layer.provide(ProviderTurnStartServiceTestkit.layer),
  Layer.provide(
    Layer.succeed(ProjectEnrichmentService.ProjectEnrichmentService, {
      peek: () =>
        Effect.succeed({
          repositoryIdentity: null,
          faviconPath: null,
          repositoryIdentityResolved: false,
        }),
      request: () => Effect.void,
      readRepositoryIdentity: () => Effect.succeed(null),
      getAvailable: () =>
        Effect.succeed({
          repositoryIdentity: null,
          faviconPath: null,
          repositoryIdentityResolved: false,
        }),
      invalidate: () => Effect.void,
      subscribeChanges: Effect.never,
    }),
  ),
  Layer.provide(McpSessionRegistryTestkit.layer),
  Layer.provide(McpProviderSessions.layer),
  Layer.provide(SqlitePersistence.layerMemory),
  Layer.provide(layerCheckpointStoreTest),
  Layer.provide(layerServerConfig),
  Layer.provide(ServerSettings.layerTest()),
  Layer.provide(layerTestProviderInstanceRegistry),
  Layer.provide(layerPlatformTest),
);

// ProviderContinuationService consumes the orchestrator's continuation queue, as in production.
const layerContinuationWorkerTest = ProviderContinuationService.layer.pipe(
  Layer.provide(Layer.merge(ProviderContinuationRequests.layer, IdAllocator.layer)),
  Layer.provideMerge(layerTest),
);

const seedParentWithTerminalTask = (input: {
  readonly threadId: ThreadId;
  readonly projectId: ProjectId;
  readonly runId: RunId;
  readonly rootNodeId: NodeId;
  readonly taskId: NodeId;
  readonly deliveryState: "pending" | "delivered" | "claimed" | "acknowledged" | "disposed";
  readonly completionWake?: "always" | "settled_only";
  readonly deliveryTaskIds?: ReadonlyArray<NodeId>;
  readonly parentRunStatus?: "running" | "completed";
  readonly siblingTasks?: ReadonlyArray<{
    readonly id: NodeId;
    readonly deliveryState: "delivered" | "claimed";
  }>;
  readonly now: DateTime.Utc;
}) =>
  Effect.gen(function* () {
    const projects = yield* ProjectService.ProjectService;
    const orchestrator = yield* Orchestrator.OrchestratorV2;
    const eventSink = yield* EventSink.EventSinkV2;
    const providerThreadId = ProviderThreadId.make(
      `provider-thread:${String(input.threadId).replace("thread:", "")}`,
    );

    yield* projects.create({
      commandId: CommandId.make(`command:seed-project:${input.threadId}`),
      projectId: input.projectId,
      title: "Delegated completion delivery",
      workspaceRoot: `/workspace/${input.projectId}`,
    });

    yield* orchestrator.dispatch({
      type: "thread.create",
      createdBy: "user",
      creationSource: "web",
      commandId: CommandId.make(`command:seed-create:${input.threadId}`),
      threadId: input.threadId,
      projectId: input.projectId,
      title: "Delegated completion delivery",
      modelSelection,
      runtimeMode: "full-access",
      interactionMode: "default",
      branch: null,
      worktreePath: null,
    });

    yield* eventSink.write({
      commandId: CommandId.make(`command:seed-projection:${input.threadId}`),
      events: [
        {
          id: EventId.make(`event:seed-provider-thread:${input.threadId}`),
          type: "provider-thread.updated",
          threadId: input.threadId,
          driver,
          providerInstanceId: modelSelection.instanceId,
          occurredAt: input.now,
          payload: {
            id: providerThreadId,
            driver,
            providerInstanceId: modelSelection.instanceId,
            providerSessionId: null,
            appThreadId: input.threadId,
            ownerNodeId: input.rootNodeId,
            nativeThreadRef: {
              driver,
              nativeId: `native:${input.threadId}`,
              strength: "strong",
            },
            nativeConversationHeadRef: null,
            status: "active",
            firstRunOrdinal: 1,
            lastRunOrdinal: 1,
            handoffIds: [],
            forkedFrom: null,
            createdAt: input.now,
            updatedAt: input.now,
          },
        },
        {
          id: EventId.make(`event:seed-run:${input.threadId}`),
          type: "run.updated",
          threadId: input.threadId,
          runId: input.runId,
          nodeId: input.rootNodeId,
          providerInstanceId: modelSelection.instanceId,
          occurredAt: input.now,
          payload: {
            id: input.runId,
            threadId: input.threadId,
            ordinal: 1,
            providerInstanceId: modelSelection.instanceId,
            modelSelection,
            providerThreadId,
            userMessageId: MessageId.make(`message:seed-user:${input.threadId}`),
            rootNodeId: input.rootNodeId,
            activeAttemptId: null,
            status: input.parentRunStatus ?? "running",
            requestedAt: input.now,
            startedAt: input.now,
            completedAt: input.parentRunStatus === "completed" ? input.now : null,
            checkpointId: null,
            contextHandoffId: null,
            delegatedCompletion: {
              disposition: "open",
              nextGeneration: 2,
              delivery:
                input.deliveryTaskIds === undefined
                  ? null
                  : {
                      generation: 1,
                      messageId: MessageId.make(`message:delegated-delivery:${input.threadId}`),
                      taskIds: input.deliveryTaskIds,
                    },
            },
          },
        },
        ...[
          { id: input.taskId, deliveryState: input.deliveryState },
          ...(input.siblingTasks ?? []),
        ].map((task) => ({
          id: EventId.make(`event:seed-task:${input.threadId}:${task.id}`),
          type: "subagent.updated" as const,
          threadId: input.threadId,
          runId: input.runId,
          nodeId: task.id,
          driver,
          providerInstanceId: modelSelection.instanceId,
          occurredAt: input.now,
          payload: {
            id: task.id,
            threadId: input.threadId,
            runId: input.runId,
            parentNodeId: input.rootNodeId,
            origin: "app_owned" as const,
            createdBy: "agent" as const,
            driver,
            providerInstanceId: modelSelection.instanceId,
            providerThreadId: null,
            childThreadId: null,
            nativeTaskRef: null,
            prompt: "Inspect the delivered ownership edge.",
            title: null,
            model: null,
            completionWake: input.completionWake ?? "settled_only",
            completionDelivery: {
              state: task.deliveryState,
              observedByRunId: task.deliveryState === "acknowledged" ? input.runId : null,
            },
            status: "completed" as const,
            result: "child finished",
            startedAt: input.now,
            completedAt: input.now,
            updatedAt: input.now,
          },
        })),
      ],
    });
  });


const runEvent = (input: {
  readonly threadId: ThreadId;
  readonly runId: RunId;
  readonly ordinal: number;
  readonly status: OrchestrationV2Run["status"];
  readonly now: DateTime.Utc;
  readonly providerThreadId?: ProviderThreadId;
  readonly userMessageId?: MessageId;
  readonly delegatedCompletion?: OrchestrationV2Run["delegatedCompletion"];
}) => ({
  id: EventId.make(`event:${input.runId}:${input.status}`),
  type: "run.updated" as const,
  threadId: input.threadId,
  runId: input.runId,
  providerInstanceId: modelSelection.instanceId,
  occurredAt: input.now,
  payload: {
    id: input.runId,
    threadId: input.threadId,
    ordinal: input.ordinal,
    providerInstanceId: modelSelection.instanceId,
    modelSelection,
    providerThreadId: input.providerThreadId ?? null,
    userMessageId: input.userMessageId ?? MessageId.make(`message:${input.runId}`),
    rootNodeId: null,
    activeAttemptId: null,
    status: input.status,
    requestedAt: input.now,
    startedAt: input.now,
    completedAt: input.status === "running" ? null : input.now,
    checkpointId: null,
    contextHandoffId: null,
    ...(input.delegatedCompletion === undefined
      ? {}
      : { delegatedCompletion: input.delegatedCompletion }),
  },
});


const queueCompletionWakeBesideRunningSibling = (key: string) =>
  Effect.gen(function* () {
    const orchestrator = yield* Orchestrator.OrchestratorV2;
    const sink = yield* EventSink.EventSinkV2;
    const now = yield* DateTime.now;
    const threadId = ThreadId.make(`${key}-parent`);
    const originRunId = RunId.make(`${key}-origin`);
    const originRootId = NodeId.make(`${key}-origin-root`);
    const incomingTaskId = NodeId.make(`${key}-incoming`);
    yield* seedParentWithTerminalTask({
      threadId,
      projectId: ProjectId.make(`${key}-project`),
      runId: originRunId,
      rootNodeId: originRootId,
      taskId: incomingTaskId,
      deliveryState: "claimed",
      deliveryTaskIds: [incomingTaskId],
      completionWake: "always",
      now,
    });
    yield* sink.write({
      events: [
        {
          id: EventId.make(`event:${key}-origin-root`),
          type: "node.updated",
          threadId,
          runId: originRunId,
          nodeId: originRootId,
          occurredAt: now,
          payload: {
            id: originRootId,
            threadId,
            runId: originRunId,
            parentNodeId: null,
            rootNodeId: originRootId,
            kind: "root_turn",
            status: "running",
            countsForRun: true,
            providerThreadId: null,
            providerTurnId: null,
            nativeItemRef: null,
            runtimeRequestId: null,
            checkpointScopeId: null,
            startedAt: now,
            completedAt: null,
          },
        },
      ],
    });
    yield* captureDispatch(orchestrator,{
      type: "delegated_task.request",
      createdBy: "agent",
      creationSource: "mcp",
      commandId: CommandId.make(`${key}-sibling`),
      parentThreadId: threadId,
      parentRunId: originRunId,
      parentNodeId: originRootId,
      task: "Keep working",
      modelSelection,
      runtimeMode: "full-access",
      interactionMode: "default",
      completionWake: "always",
    });
    const seeded = yield* orchestrator.getThreadProjection(threadId);
    const origin = seeded.runs.find((run) => run.id === originRunId)!;
    const sibling = seeded.subagents.find((task) => task.id !== incomingTaskId)!;
    // The coordinator finished its spawning turn but is busy with another run, so the wake queues.
    yield* sink.write({
      events: [
        {
          ...runEvent({ threadId, runId: originRunId, ordinal: 1, status: "completed", now }),
          payload: { ...origin, status: "completed", completedAt: now },
        },
        runEvent({
          threadId,
          runId: RunId.make(`${key}-busy`),
          ordinal: 2,
          status: "running",
          now,
        }),
      ],
    });
    const delivery = origin.delegatedCompletion!.delivery!;
    yield* captureDispatch(orchestrator,{
      type: "message.dispatch",
      createdBy: "agent",
      creationSource: "server",
      commandId: CommandId.make(`${key}-wake`),
      threadId,
      messageId: delivery.messageId,
      text: "Delegated task completed",
      attachments: [],
      modelSelection,
      dispatchMode: { type: "queue_after_active" },
      delegatedCompletion: {
        parentRunId: originRunId,
        generation: delivery.generation,
        taskIds: delivery.taskIds,
      },
    });
    const wake = (yield* orchestrator.getThreadProjection(threadId)).runs.find(
      (run) => run.userMessageId === delivery.messageId,
    )!;
    assert.equal(wake.status, "queued");
    const completeSibling = Effect.gen(function* () {
      const childRun = (yield* orchestrator.getThreadProjection(sibling.childThreadId!)).runs[0]!;
      const afterSequence = yield* sink.latestSequence();
      yield* sink.write({
        events: [
          {
            ...runEvent({
              threadId: sibling.childThreadId!,
              runId: childRun.id,
              ordinal: childRun.ordinal,
              status: "completed",
              now,
            }),
            payload: { ...childRun, status: "completed", completedAt: now },
          },
        ],
      });
      return afterSequence;
    });
    return {
      orchestrator,
      sink,
      now,
      threadId,
      originRunId,
      incomingTaskId,
      sibling,
      delivery,
      wake,
      completeSibling,
    };
  });


const captureDir=process.env.CAPTURE_DIR!;
const side=process.env.CAPTURE_SIDE!;
const transcript: Array<{label:string;data:unknown}>=[];
const scrub=(value:unknown):unknown=>Array.isArray(value)?value.map(scrub):value&&typeof value==='object'?Object.fromEntries(Object.entries(value).filter(([key])=>!['modelSelection','model','nativeThreadRef','nativeItemRef'].includes(key)).map(([key,item])=>[key,scrub(item)])):value;
const record=(label:string,data:unknown)=>{transcript.push({label,data:scrub(data)});fs.writeFileSync(captureDir+'/C2-harness.md','# C2 — HARNESS transcript (not server RPC)\n\nReal orchestrator, event sink, SQLite memory persistence, continuation service and projection layers; stub provider. Direct synthetic sink writes establish the otherwise unavailable pending-sibling ordering. No HTTP/WebSocket server or paid provider turn.\n\n'+transcript.map(x=>`## ${x.label}\n\n\`\`\`json\n${JSON.stringify(x.data,null,2)}\n\`\`\`\n`).join('\n'));};
const captureDispatch=(orchestrator:Orchestrator.OrchestratorV2["Service"],command:Parameters<Orchestrator.OrchestratorV2["Service"]["dispatch"]>[0])=>Effect.gen(function*(){record('fixture orchestrator.dispatch',command);const result=yield* orchestrator.dispatch(command);record('fixture persisted receipt',result);return result;});
const program=Effect.gen(function*(){
 record('environment',{side,node:process.version,kind:'harness',provider:'stub; no real provider session',database:'fresh in-memory SQLite',fixture:'A claimed by queued wake W; B completed and pending outside W'});
 const {orchestrator,sink,now,threadId,originRunId,sibling,delivery,wake}=yield* queueCompletionWakeBesideRunningSibling(`capture-C2-${side}`);
 const before=yield* orchestrator.getThreadProjection(threadId);
 const original=before.subagents.find(task=>task.id===sibling.id)!;
 const taskB={...original,status:'completed' as const,result:'Synthetic already-completed B result',completedAt:now,updatedAt:now,completionDelivery:{state:'pending' as const,observedByRunId:null}};
 const event={id:EventId.make(`capture-C2-${side}-seed-ready-B`),type:'subagent.updated' as const,threadId,runId:originRunId,nodeId:sibling.id,driver,providerInstanceId:modelSelection.instanceId,occurredAt:now,payload:taskB};
 record('HARNESS SEED eventSink.write — exact ready-before-cancel boundary',event);
 yield* sink.write({events:[event]});
 record('persisted projection before cancel',yield* orchestrator.getThreadProjection(threadId));
 const afterSequence=yield* sink.latestSequence();
 const command={type:'queued-run.cancel' as const,commandId:CommandId.make(`capture-C2-${side}-cancel`),threadId,runId:wake.id};
 record('orchestrator.dispatch (same command as RPC)',command);
 const result=yield* orchestrator.dispatch(command);
 record('command receipt with persisted storedEvents',result);
 if(side==='after'){
   yield* sink.stream({afterSequence,eventType:'message.updated'}).pipe(Stream.filter(stored=>stored.event.type==='message.updated'&&stored.event.payload.delegatedCompletion?.taskIds.includes(sibling.id)===true&&stored.event.payload.id!==delivery.messageId),Stream.take(1),Stream.tap(stored=>Effect.sync(()=>record('actual successor message persisted by ProviderContinuationService',stored))),Stream.runDrain);
 }
 const delivered=yield* orchestrator.getThreadProjection(threadId);
 const busy=delivered.runs.find(run=>run.status==='running')!;
 const busyTerminal={...runEvent({threadId,runId:busy.id,ordinal:busy.ordinal,status:'completed',now}),payload:{...busy,status:'completed' as const,completedAt:now}};
 record('HARNESS SEED finish busy parent through persisted event',busyTerminal);
 yield* sink.write({events:[busyTerminal]});
 yield* orchestrator.resumeQueuedRuns;
 const final=yield* orchestrator.getThreadProjection(threadId);
 record('persisted projection after cancel and continuation milestone',final);
 const messages=final.messages.filter(m=>m.delegatedCompletion?.taskIds.includes(sibling.id)&&m.id!==delivery.messageId);
 const summary={row:'C2',side,kind:'harness',wake:final.runs.find(r=>r.id===wake.id),cohort:final.runs.find(r=>r.id===originRunId)?.delegatedCompletion,tasks:final.subagents,successorMessages:messages,successorRuns:final.runs.filter(r=>messages.some(m=>m.id===r.userMessageId))};
 record('row result',summary);
 fs.writeFileSync(captureDir+'/C2-result.json',JSON.stringify(scrub(summary),null,2));
 console.log(JSON.stringify(scrub(summary),null,2));
});
await Effect.runPromise(program.pipe(Effect.provide(layerContinuationWorkerTest),Effect.scoped));
