// The network-policy types are copied verbatim from the installed just-bash at
// vendor time (see scripts/vendor-compiled/just-bash.mjs) so the credential-
// brokering surface (allowedUrlPrefixes + header transforms) never drifts.
import type { NetworkConfig } from "./network/types.js";

export type {
  AllowedUrl,
  AllowedUrlEntry,
  HttpMethod,
  NetworkConfig,
  RequestTransform,
} from "./network/types.js";

export type InitialFileContent = string | Uint8Array;
export type InitialFiles = Record<string, InitialFileContent>;

export interface IFileSystem {
  getAllPaths(): string[];
  mkdir(path: string, options?: { recursive?: boolean | undefined }): Promise<void>;
  readFileBuffer(path: string): Promise<Uint8Array>;
  rm(
    path: string,
    options?: { force?: boolean | undefined; recursive?: boolean | undefined },
  ): Promise<void>;
  stat(path: string): Promise<{
    isDirectory: boolean;
    isFile: boolean;
    isSymbolicLink: boolean;
  }>;
  writeFile(path: string, content: InitialFileContent): Promise<void>;
}

export interface BeveOptions {
  cwd: string;
  env?: Readonly<Record<string, string>> | undefined;
  fs: IFileSystem;
  network?: NetworkConfig | undefined;
}

export interface BeveExecResult {
  exitCode: number;
  stderr: string;
  stdout: string;
}

export declare class Bash {
  constructor(options: BeveOptions);
  dispose?(): Promise<void> | void;
  exec(command: string): Promise<BeveExecResult>;
  getEnv(): Record<string, string>;
}

export declare class InMemoryFs implements IFileSystem {
  constructor(files?: InitialFiles);
  getAllPaths(): string[];
  mkdir(path: string, options?: { recursive?: boolean | undefined }): Promise<void>;
  readFileBuffer(path: string): Promise<Uint8Array>;
  rm(
    path: string,
    options?: { force?: boolean | undefined; recursive?: boolean | undefined },
  ): Promise<void>;
  stat(path: string): Promise<{
    isDirectory: boolean;
    isFile: boolean;
    isSymbolicLink: boolean;
  }>;
  writeFile(path: string, content: InitialFileContent): Promise<void>;
}

export interface ReadWriteFsOptions {
  allowSymlinks?: boolean | undefined;
  maxFileReadSize?: number | undefined;
  root: string;
}

export declare class ReadWriteFs implements IFileSystem {
  constructor(options: ReadWriteFsOptions);
  getAllPaths(): string[];
  mkdir(path: string, options?: { recursive?: boolean | undefined }): Promise<void>;
  readFileBuffer(path: string): Promise<Uint8Array>;
  rm(
    path: string,
    options?: { force?: boolean | undefined; recursive?: boolean | undefined },
  ): Promise<void>;
  stat(path: string): Promise<{
    isDirectory: boolean;
    isFile: boolean;
    isSymbolicLink: boolean;
  }>;
  writeFile(path: string, content: InitialFileContent): Promise<void>;
}

export interface SandboxOptions {
  cwd?: string | undefined;
  env?: Record<string, string> | undefined;
  fs?: IFileSystem | undefined;
  network?: NetworkConfig | undefined;
  timeoutMs?: number | undefined;
}

export interface SandboxRunCommandParams {
  cmd: string;
  args?: string[] | undefined;
  cwd?: string | undefined;
  env?: Record<string, string> | undefined;
  detached?: boolean | undefined;
  signal?: AbortSignal | undefined;
}

export interface SandboxCommandOutputMessage {
  type: "stdout" | "stderr";
  data: string;
  timestamp: Date;
}

export declare class SandboxCommand {
  readonly cmdId: string;
  readonly cwd: string;
  readonly startedAt: Date;
  exitCode: number | undefined;
  logs(): AsyncGenerator<SandboxCommandOutputMessage, void, unknown>;
  wait(): Promise<SandboxCommandFinished>;
  output(): Promise<string>;
  stdout(): Promise<string>;
  stderr(): Promise<string>;
  kill(): Promise<void>;
}

export interface SandboxCommandFinished extends SandboxCommand {
  exitCode: number;
}

export declare class Sandbox {
  static create(opts?: SandboxOptions): Promise<Sandbox>;
  runCommand(params: SandboxRunCommandParams & { detached: true }): Promise<SandboxCommand>;
  runCommand(params: SandboxRunCommandParams): Promise<SandboxCommandFinished>;
  stop(): Promise<void>;
  get bashEnvInstance(): Bash;
}
