/**
 * Orb Project Run — Integration Glue Entry Point
 *
 * Connects OrbProjectManager (packages/agents/src/orb/orb-project-manager.ts)
 * to the Orb runtime (Docker + AgentOS + OpenCode) and the Git/Gitea lifecycle
 * (packages/agents/src/orb/git-adapter.ts). This is the missing connection
 * point: OrbProjectManager was fully implemented and live-tested but had no
 * production entry point — no Convex action, no script invocation.
 *
 * Usage:
 *   ORB_RUN=1 \
 *   ORB_GATEWAY_API_KEY=... \
 *   ORB_GATEWAY_BASE_URL=https://ai.example.com/v1 \
 *   ORB_GATEWAY_MODEL=glm-5.2 \
 *   ORB_GATEWAY_PROVIDER=cheaptricks \
   GITEA_URL=https://git.example.com \
   GITEA_TOKEN=... \
   ORB_RUN_REPOSITORY_URL=https://git.example.com/owner/repo.git \
   ORB_RUN_REPOSITORY_PATH=owner/repo \
   bun run scripts/orb-project-run.ts
 *
 * Stable markers: ORB_RUN_COMPLETED (exit 0), ORB_RUN_BLOCKED (exit 2),
 * ORB_RUN_FAILED (exit 1). The script never prints gateway secrets; only
 * provider/model identifiers and sanitized status text.
 *
 * See docs/DOGFOOD_V0.md for the full lifecycle and the relationship between
 * this entry point, the Flue project-manager agent, and the web start button.
 */
/* eslint-disable no-console -- CLI tool */

import { createGiteaHttpTransport } from "../packages/agents/src/git/gitea";
import type { OrbModelGatewayConfig } from "../packages/agents/src/orb/domain";
import { createGitLifecyclePort } from "../packages/agents/src/orb/git-adapter";
import { createOrbAdapter } from "../packages/agents/src/orb/orb-adapter";
import { OrbProjectManager } from "../packages/agents/src/orb/orb-project-manager";

const MARKER = {
  blocked: "ORB_RUN_BLOCKED",
  completed: "ORB_RUN_COMPLETED",
  failed: "ORB_RUN_FAILED",
} as const;

interface RunConfig {
  readonly gateway: OrbModelGatewayConfig;
  readonly giteaToken: string | undefined;
  readonly giteaUrl: string | undefined;
  readonly issueBody: string;
  readonly issueNumber: number;
  readonly issueTitle: string;
  readonly repositoryPath: string | undefined;
  readonly repositoryUrl: string | undefined;
  readonly baseBranch: string;
  readonly workspaceRoot: string;
}

const envValue = (key: string): string | undefined => process.env[key];

const resolveGateway = (): OrbModelGatewayConfig | null => {
  const apiKey =
    envValue("ORB_GATEWAY_API_KEY") ?? envValue("AGENT_MODEL_API_KEY");
  const baseUrl =
    envValue("ORB_GATEWAY_BASE_URL") ?? envValue("AGENT_MODEL_BASE_URL");
  const model = envValue("ORB_GATEWAY_MODEL") ?? envValue("AGENT_MODEL_NAME");
  const provider =
    envValue("ORB_GATEWAY_PROVIDER") ?? envValue("AGENT_MODEL_PROVIDER");
  if (
    !apiKey?.trim() ||
    !baseUrl?.trim() ||
    !model?.trim() ||
    !provider?.trim()
  ) {
    return null;
  }
  return { apiKey, baseUrl, model, provider };
};

const resolveConfig = (): RunConfig | null => {
  const gateway = resolveGateway();
  if (!gateway) {
    return null;
  }
  const issueTitle = envValue("ORB_RUN_ISSUE_TITLE") ?? "Orb run: echo test";
  const issueBody =
    envValue("ORB_RUN_ISSUE_BODY") ??
    "Reply with WORK_COMPLETE: orb project run succeeded";
  return {
    baseBranch: envValue("ORB_RUN_BASE_BRANCH") ?? "main",
    gateway,
    giteaToken: envValue("GITEA_TOKEN") ?? envValue("ORB_RUN_GITEA_TOKEN"),
    giteaUrl: envValue("GITEA_URL") ?? envValue("ORB_RUN_GITEA_URL"),
    issueBody,
    issueNumber: Number(envValue("ORB_RUN_ISSUE_NUMBER") ?? "1"),
    issueTitle,
    repositoryPath:
      envValue("ORB_RUN_REPOSITORY_PATH") ??
      envValue("ZOPU_SMOKE_REPOSITORY_PATH"),
    repositoryUrl: envValue("ORB_RUN_REPOSITORY_URL"),
    workspaceRoot:
      envValue("ORB_DOCKER_WORKSPACE") ?? `/tmp/orb-project-run-${Date.now()}`,
  };
};

const runComplete = async (): Promise<number> => {
  const config = resolveConfig();
  if (!config) {
    console.error(
      "[orb-run] missing gateway config: set ORB_GATEWAY_* (or AGENT_MODEL_* fallbacks)."
    );
    console.log(`\n${MARKER.blocked}`);
    return 2;
  }

  const {
    baseBranch,
    gateway,
    giteaToken,
    giteaUrl,
    issueBody,
    issueNumber,
    issueTitle,
    repositoryPath,
    repositoryUrl,
    workspaceRoot,
  } = config;

  console.log(
    `[orb-run] gateway provider=${gateway.provider} model=${gateway.model}`
  );

  // The Orb adapter wraps the OrbRuntime (Docker + AgentOS + OpenCode).
  const orbAdapter = createOrbAdapter();
  const events: { type: string; text?: string }[] = [];

  // The Git lifecycle adapter connects Orb sandbox commands to Gitea PR
  // creation. If Gitea is not configured, the Git lifecycle is skipped but
  // the Orb run still completes the model turn and repository preparation.
  const createGitLifecycle = (
    orb: Parameters<typeof createGitLifecyclePort>[0]
  ) => {
    if (!giteaUrl || !giteaToken) {
      throw new Error(
        "GITEA_URL and GITEA_TOKEN are required for the Git publish lifecycle"
      );
    }
    return createGitLifecyclePort(
      orb,
      createGiteaHttpTransport({ baseUrl: giteaUrl, token: giteaToken })
    );
  };

  const pm = new OrbProjectManager({
    createGitLifecycle,
    onProjectEvent: (e) => {
      events.push({ text: e.text, type: e.type });
      const summary = (e.text ?? e.type).slice(0, 120);
      console.log(`    [event] ${e.type}: ${summary}`);
    },
    orbAdapter,
  });

  const issueId = `orb-run-${Date.now()}`;
  const branchName = `work/orb-run-${issueNumber}-${Date.now()}`;

  let result;
  try {
    result = await pm.startIssue({
      baseBranch,
      branchName,
      context: {
        artifacts: [],
        contextFiles: [],
        issueBody,
        issueTitle,
        repositoryUrl,
      },
      contextPack: {
        artifacts: [],
        contextFiles: [],
        evidence: [],
        issueBody,
        issueNumber,
        issueTitle,
        repositoryMetadata: {
          baseBranch,
          repositoryName: repositoryPath ?? "orb-run",
          repositoryUrl: repositoryUrl ?? "local",
        },
      },
      docker: {
        hostWorkspacePath: workspaceRoot,
      },
      gateway,
      issueId,
      issueNumber,
      issueTitle,
      projectId: "orb-run",
      runId: `run-${Date.now()}`,
    });

    console.log(
      `[orb-run] session opened: ${result.sessionId ?? "?"} (status=${result.status})`
    );

    // If the run completed with a WORK_COMPLETE marker, drive the Git
    // lifecycle. If Gitea is not configured, the model turn + repository
    // preparation still constitutes a successful Orb run.
    if (result.status === "completing" || result.status === "completed") {
      if (giteaUrl && giteaToken && repositoryPath) {
        console.log("[orb-run] driving Git/Gitea lifecycle...");
        try {
          const gitResult = await pm.complete({ issueId });
          console.log(
            `[orb-run] Git lifecycle: ${gitResult.status} branch=${gitResult.branch}`
          );
        } catch (error) {
          console.log(
            `[orb-run] Git lifecycle failed: ${error instanceof Error ? error.message : String(error)}`
          );
        }
      } else {
        console.log(
          "[orb-run] Gitea not configured; skipping Git lifecycle (model turn completed)"
        );
      }
    }
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    console.error(`[orb-run] failed: ${message}`);
    await pm.cancel(issueId).catch((cancelError: unknown) => void cancelError);
    console.log(`\n${MARKER.failed}`);
    return 1;
  }

  await pm.cancel(issueId).catch((cancelError: unknown) => void cancelError);

  const eventTypes = events.map((e) => e.type);
  console.log(
    `[orb-run] events: ${[...new Set(eventTypes)].join(", ")} (${events.length} total)`
  );

  const hasSessionOpened = eventTypes.includes("run.session_opened");
  if (hasSessionOpened) {
    console.log(`\n${MARKER.completed}`);
    return 0;
  }

  console.log(`\n${MARKER.failed}`);
  return 1;
};

if (envValue("ORB_RUN") !== "1") {
  console.error(
    "Set ORB_RUN=1 to drive one issue through the Orb project-manager (requires Docker + model gateway)."
  );
  console.error(MARKER.blocked);
  process.exit(2);
}

(async () => {
  try {
    const code = await runComplete();
    process.exit(code);
  } catch (error) {
    console.error("[orb-run] unexpected failure:", error);
    console.error(MARKER.failed);
    process.exit(1);
  }
})();
