import fs from 'node:fs';
import path from 'node:path';
import { config } from '../config.js';
import { HttpError } from '../middleware/errors.js';

const activeRoot = path.join(config.storageDir, 'active', 'routes');
const trashRoot = path.join(config.storageDir, 'trash', 'routes');
const storageRoot = path.resolve(config.storageDir);

export const routeDirectory = id => path.join(activeRoot, String(id));
export const relativeStoragePath = absolute => path.relative(config.storageDir, absolute).split(path.sep).join('/');

function storedPath(relativePath) {
  const target = path.resolve(storageRoot, relativePath);
  const insideStorage = target !== storageRoot && target.startsWith(`${storageRoot}${path.sep}`);
  if (!insideStorage) throw new HttpError(500, 'Ungültiger interner Medienpfad.');
  return target;
}

function isFile(target) {
  try {
    return fs.statSync(target).isFile();
  } catch (error) {
    if (error.code === 'ENOENT') return false;
    throw error;
  }
}

export function ensureRouteDirectories(id) {
  const root = routeDirectory(id);
  [root, path.join(root, 'images'), path.join(root, 'audio')]
    .forEach(directory => fs.mkdirSync(directory, { recursive: true }));
  return root;
}

export function moveUploadedFile(uploaded, destination) {
  fs.mkdirSync(path.dirname(destination), { recursive: true });
  fs.renameSync(uploaded.path, destination);
  return relativeStoragePath(destination);
}

export function removeUpload(uploaded) {
  if (!uploaded?.path || !fs.existsSync(uploaded.path)) return;
  fs.rmSync(uploaded.path, { force: true });
}

export function removeStoredFile(relativePath) {
  if (!relativePath) return false;

  const target = storedPath(relativePath);
  if (!fs.existsSync(target)) return false;
  fs.rmSync(target, { force: true });
  return true;
}

export function softDeleteRouteDirectory(id) {
  const source = routeDirectory(id);
  if (!fs.existsSync(source)) {
    throw new HttpError(409, 'Streckenverzeichnis fehlt; Löschmarkierung wurde nicht ausgeführt.');
  }

  const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');
  const destination = path.join(trashRoot, `${id}-${timestamp}`);
  fs.renameSync(source, destination);
  return {
    sourcePrefix: relativeStoragePath(source),
    targetPrefix: relativeStoragePath(destination),
    destination
  };
}

export function restoreRouteDirectory(id, trashRelativePath) {
  const source = path.join(config.storageDir, trashRelativePath);
  const destination = routeDirectory(id);
  if (!fs.existsSync(source)) throw new HttpError(409, 'Papierkorbverzeichnis der Strecke fehlt.');
  if (fs.existsSync(destination)) throw new HttpError(409, 'Aktives Streckenverzeichnis existiert bereits.');

  fs.renameSync(source, destination);
  return {
    sourcePrefix: relativeStoragePath(source),
    targetPrefix: relativeStoragePath(destination),
    source,
    destination
  };
}

export function resolveStoredFile(relativePath) {
  if (!relativePath?.startsWith('active/')) {
    throw new HttpError(404, 'Aktive Mediendatei nicht gefunden.');
  }

  const target = storedPath(relativePath);
  if (!isFile(target)) throw new HttpError(404, 'Mediendatei nicht gefunden.');
  return target;
}
