import { join } from 'node:path';

import { NUploader } from '@nostrify/nostrify';
import { crypto } from '@std/crypto';
import { encodeHex } from '@std/encoding/hex';
import { extensionsByType } from '@std/media-types';

export interface DenoUploaderOpts {
  baseUrl: string;
  dir: string;
}

/** Local Deno filesystem uploader. */
export class DenoUploader implements NUploader {
  baseUrl: string;
  dir: string;

  constructor(opts: DenoUploaderOpts) {
    this.baseUrl = opts.baseUrl;
    this.dir = opts.dir;
  }

  async upload(file: File): Promise<[['url', string], ...string[][]]> {
    const sha256 = encodeHex(await crypto.subtle.digest('SHA-256', file.stream()));
    const ext = extensionsByType(file.type)?.[0] ?? 'bin';
    const filename = `${sha256}.${ext}`;

    await Deno.mkdir(this.dir, { recursive: true });
    await Deno.writeFile(join(this.dir, filename), file.stream());

    const url = new URL(this.baseUrl);
    const path = url.pathname === '/' ? filename : join(url.pathname, filename);

    return [
      ['url', new URL(path, url).toString()],
      ['m', file.type],
      ['x', sha256],
      ['size', file.size.toString()],
    ];
  }

  async delete(filename: string) {
    const path = join(this.dir, filename);
    await Deno.remove(path);
  }
}
