/**
 * Alice — the file CLIENT. Demonstrates the typed `@shade/files` API:
 *
 *   bun run examples/08-files-browser/alice-cli.ts list /
 *   bun run examples/08-files-browser/alice-cli.ts mkdir /docs
 *   bun run examples/08-files-browser/alice-cli.ts upload ./README.md /docs/readme.md
 *   bun run examples/08-files-browser/alice-cli.ts download /docs/readme.md ./out.md
 *   bun run examples/08-files-browser/alice-cli.ts stat /docs/readme.md
 *   bun run examples/08-files-browser/alice-cli.ts delete /docs/readme.md
 */
import { readFile, writeFile, stat as fsstat } from 'node:fs/promises';
import { createShade } from '@shade/sdk';

const PREKEY = 'http://localhost:9992';
const ALICE_BASE_URL = 'http://localhost:9993';
const BOB_BASE_URL = 'http://localhost:9994';

const alice = await createShade({ prekeyServer: PREKEY, address: 'alice' });
alice.configureTransfers({
  resolveBaseUrl: async (peer) => {
    if (peer === 'bob') return BOB_BASE_URL;
    throw new Error(`alice: unknown peer ${peer}`);
  },
});
const app = await alice.transferRoute();
Bun.serve({ port: 9993, fetch: app.fetch });

const fs = await alice.files.client('bob', { defaultTimeoutMs: 30_000 });

const [cmd, ...args] = process.argv.slice(2);
try {
  switch (cmd) {
    case 'list': {
      const path = args[0] ?? '/';
      const result = await fs.list(path);
      for (const e of result.entries) {
        console.log(`${e.kind === 'dir' ? 'd' : '-'}  ${String(e.size).padStart(10)}  ${e.name}`);
      }
      break;
    }
    case 'stat': {
      const path = args[0]!;
      const e = await fs.stat(path);
      console.log(JSON.stringify(e, null, 2));
      break;
    }
    case 'mkdir': {
      const path = args[0]!;
      const r = await fs.mkdir(path, { recursive: true });
      console.log(`created ${r.entry.name}`);
      break;
    }
    case 'delete': {
      const path = args[0]!;
      const r = await fs.delete(path, { recursive: true });
      console.log(`deleted ${r.deletedCount} entrie(s)`);
      break;
    }
    case 'upload': {
      const localPath = args[0]!;
      const remotePath = args[1]!;
      const bytes = new Uint8Array(await readFile(localPath));
      const s = await fsstat(localPath);
      console.log(`uploading ${s.size} bytes → ${remotePath}`);
      const r = await fs.write(remotePath, bytes, { overwrite: true });
      console.log(`done — remote size: ${r.entry.size}`);
      break;
    }
    case 'download': {
      const remotePath = args[0]!;
      const localPath = args[1]!;
      const result = await fs.read(remotePath);
      if (result.kind === 'inline') {
        await writeFile(localPath, result.bytes);
        console.log(`downloaded ${result.bytes.byteLength} bytes (inline) sha256=${result.sha256}`);
      } else {
        const reader = result.stream.getReader();
        const chunks: Uint8Array[] = [];
        let total = 0;
        while (true) {
          const { value, done } = await reader.read();
          if (done) break;
          if (value !== undefined) {
            chunks.push(value);
            total += value.byteLength;
          }
        }
        reader.releaseLock();
        const out = new Uint8Array(total);
        let offset = 0;
        for (const c of chunks) {
          out.set(c, offset);
          offset += c.byteLength;
        }
        await writeFile(localPath, out);
        await result.done();
        console.log(`downloaded ${total} bytes (streamed) sha256=${result.sha256}`);
      }
      break;
    }
    default:
      console.error('Usage: alice-cli.ts <list|stat|mkdir|delete|upload|download> [args...]');
      process.exit(1);
  }
} finally {
  await alice.shutdown();
  process.exit(0);
}
