/**
 * Centralized dependency imports for Onebox.
 */

// Node.js native scope
import * as path from 'node:path';
import * as nodeFs from 'node:fs';
import * as nodeFsPromises from 'node:fs/promises';
import * as nodeHttps from 'node:https';
import * as nodeHttp from 'node:http';
import * as nodeNet from 'node:net';
import * as nodeOs from 'node:os';
import * as nodeCrypto from 'node:crypto';
import * as nodeStream from 'node:stream';
import * as nodeUrl from 'node:url';
import { spawn } from 'node:child_process';

export { path, nodeFs, nodeHttps, nodeHttp, nodeNet, nodeOs, nodeCrypto, nodeStream, nodeUrl };

export const fs = {
  mkdir: nodeFsPromises.mkdir,
  mkdtemp: nodeFsPromises.mkdtemp,
  readFile: nodeFsPromises.readFile,
  writeFile: nodeFsPromises.writeFile,
  rename: nodeFsPromises.rename,
  stat: async (filePathArg: string) => {
    const stats = await nodeFsPromises.stat(filePathArg);
    return {
      ...stats,
      size: stats.size,
      isFile: stats.isFile(),
      isDirectory: stats.isDirectory(),
      isSymlink: stats.isSymbolicLink(),
    };
  },
  remove: async (filePathArg: string, optionsArg: { recursive?: boolean } = {}) => {
    await nodeFsPromises.rm(filePathArg, { recursive: optionsArg.recursive ?? false });
  },
  readTextFile: async (filePathArg: string) => nodeFsPromises.readFile(filePathArg, 'utf8'),
  writeTextFile: async (filePathArg: string, dataArg: string) => {
    await nodeFsPromises.writeFile(filePathArg, dataArg, 'utf8');
  },
  readDir: async function* (dirPathArg: string) {
    const entries = await nodeFsPromises.readdir(dirPathArg, { withFileTypes: true });
    for (const entry of entries) {
      yield {
        name: entry.name,
        isFile: entry.isFile(),
        isDirectory: entry.isDirectory(),
        isSymlink: entry.isSymbolicLink(),
      };
    }
  },
};

export const encoding = {
  encodeBase64: (dataArg: Uint8Array | string) => Buffer.from(dataArg).toString('base64'),
  decodeBase64: (dataArg: string) => new Uint8Array(Buffer.from(dataArg, 'base64')),
};

export const crypto = globalThis.crypto;

export const isNotFoundError = (errorArg: unknown) =>
  typeof errorArg === 'object' && errorArg !== null && 'code' in errorArg && errorArg.code === 'ENOENT';

export const isAlreadyExistsError = (errorArg: unknown) =>
  typeof errorArg === 'object' && errorArg !== null && 'code' in errorArg && errorArg.code === 'EEXIST';

export interface ICommandOptions {
  args?: string[];
  stdin?: 'null' | 'piped' | 'inherit';
  stdout?: 'piped' | 'inherit' | 'null';
  stderr?: 'piped' | 'inherit' | 'null';
  input?: Uint8Array | string;
}

export interface ICommandOutput {
  code: number;
  success: boolean;
  stdout: Uint8Array;
  stderr: Uint8Array;
}

export const runCommand = async (
  commandArg: string,
  optionsArg: ICommandOptions = {},
): Promise<ICommandOutput> => {
  const child = spawn(commandArg, optionsArg.args ?? [], {
    stdio: [
      optionsArg.stdin === 'inherit' ? 'inherit' : optionsArg.stdin === 'null' ? 'ignore' : 'pipe',
      optionsArg.stdout === 'inherit' ? 'inherit' : optionsArg.stdout === 'null' ? 'ignore' : 'pipe',
      optionsArg.stderr === 'inherit' ? 'inherit' : optionsArg.stderr === 'null' ? 'ignore' : 'pipe',
    ],
  });

  const stdoutChunks: Buffer[] = [];
  const stderrChunks: Buffer[] = [];
  if (child.stdout) {
    child.stdout.on('data', (chunk: Buffer) => stdoutChunks.push(chunk));
  }
  if (child.stderr) {
    child.stderr.on('data', (chunk: Buffer) => stderrChunks.push(chunk));
  }
  if (child.stdin) {
    if (optionsArg.input) {
      child.stdin.end(optionsArg.input);
    } else if (optionsArg.stdin !== 'inherit') {
      child.stdin.end();
    }
  }

  const code = await new Promise<number>((resolve, reject) => {
    child.once('error', reject);
    child.once('close', (exitCode) => resolve(exitCode ?? 0));
  });

  return {
    code,
    success: code === 0,
    stdout: Buffer.concat(stdoutChunks),
    stderr: Buffer.concat(stderrChunks),
  };
};

// @push.rocks scope
import * as smartdb from '@push.rocks/smartdb';
import * as smartdata from '@push.rocks/smartdata';
import * as smartacme from '@push.rocks/smartacme';
import * as smartregistry from '@push.rocks/smartregistry';
import * as smartstorage from '@push.rocks/smartstorage';
import * as taskbuffer from '@push.rocks/taskbuffer';
import * as smartguard from '@push.rocks/smartguard';
import * as smartjwt from '@push.rocks/smartjwt';
import * as smartmcp from '@push.rocks/smartmcp';
export { smartdb, smartdata, smartacme, smartregistry, smartstorage, taskbuffer, smartguard, smartjwt, smartmcp };

// API infrastructure
import * as typedrequest from '@api.global/typedrequest';
import * as typedrequestInterfaces from '@api.global/typedrequest-interfaces';
import * as typedserver from '@api.global/typedserver';
export { typedrequest, typedrequestInterfaces, typedserver };

// WebAuthn/passkey verification
import * as simplewebauthnServer from '@simplewebauthn/server';
export { simplewebauthnServer };

// Docker API Client
import { DockerHost } from '@apiclient.xyz/docker';
export const docker = { Docker: DockerHost };

// Cloudflare DNS Management (API Client)
import * as cloudflare from '@apiclient.xyz/cloudflare';
export { cloudflare };

// AWS S3 client for S3-compatible object operations
import {
  S3Client,
  ListObjectsV2Command,
  GetObjectCommand,
  PutObjectCommand,
} from '@aws-sdk/client-s3';
export const awsS3 = {
  S3Client,
  ListObjectsV2Command,
  GetObjectCommand,
  PutObjectCommand,
};

// Backup archive (content-addressed dedup storage)
import { ContainerArchive } from '@serve.zone/containerarchive';
export { ContainerArchive };

// serve.zone App Store contracts and resolver
import * as servezoneInterfaces from '@serve.zone/interfaces';
import * as servezoneAppstore from '@serve.zone/appstore';
export { servezoneInterfaces, servezoneAppstore };
