/**
 * Filesystem backup transport — pushes the bundle to a configured directory
 * (a mounted volume / NAS share). The simplest destination: no network, just a
 * path the app can write to.
 */

import { constants } from 'node:fs';
import { access, copyFile, readdir, stat, unlink } from 'node:fs/promises';
import path from 'node:path';

import {
  BACKUP_NAME_PREFIX,
  sortBundlesNewestFirst,
  type BackupTransport,
  type FilesystemDestConfig,
} from './types';

export class FilesystemTransport implements BackupTransport {
  constructor(private readonly cfg: FilesystemDestConfig) {}

  async test(): Promise<void> {
    if (!this.cfg.directory) throw new Error('No directory configured');
    await access(this.cfg.directory, constants.W_OK).catch(() => {
      throw new Error(`Directory not writable or does not exist: ${this.cfg.directory}`);
    });
    const s = await stat(this.cfg.directory);
    if (!s.isDirectory()) throw new Error(`Not a directory: ${this.cfg.directory}`);
  }

  async push(localPath: string, remoteName: string): Promise<{ remoteRef: string; bytes: number }> {
    const dest = path.join(this.cfg.directory, remoteName);
    await copyFile(localPath, dest);
    const s = await stat(dest);
    return { remoteRef: dest, bytes: s.size };
  }

  async prune(retentionCount: number | null): Promise<{ deleted: number }> {
    if (retentionCount === null || retentionCount < 0) return { deleted: 0 };
    const entries = await readdir(this.cfg.directory);
    const bundles = sortBundlesNewestFirst(entries.filter((n) => n.startsWith(BACKUP_NAME_PREFIX)));
    const toDelete = bundles.slice(retentionCount);
    for (const name of toDelete) {
      await unlink(path.join(this.cfg.directory, name)).catch(() => {});
    }
    return { deleted: toDelete.length };
  }
}
