import fs from 'fs';
import os from 'os';
import path from 'path';

const PACKAGED_DATA_DIRECTORY_NAME = 'MetoYou Server';

type PackagedProcess = NodeJS.Process & { pkg?: unknown };

function uniquePaths(paths: string[]): string[] {
  return [...new Set(paths.map((candidate) => path.resolve(candidate)))];
}

export function isPackagedRuntime(): boolean {
  return Boolean((process as PackagedProcess).pkg);
}

export function getRuntimeBaseDir(): string {
  return isPackagedRuntime()
    ? path.dirname(process.execPath)
    : process.cwd();
}

export function resolveRuntimePath(...segments: string[]): string {
  return path.join(getRuntimeBaseDir(), ...segments);
}

function resolvePackagedDataDirectory(): string {
  const homeDirectory = os.homedir();

  switch (process.platform) {
    case 'win32':
      return path.join(
        process.env.APPDATA || path.join(homeDirectory, 'AppData', 'Roaming'),
        PACKAGED_DATA_DIRECTORY_NAME
      );
    case 'darwin':
      return path.join(homeDirectory, 'Library', 'Application Support', PACKAGED_DATA_DIRECTORY_NAME);
    default:
      return path.join(
        process.env.XDG_DATA_HOME || path.join(homeDirectory, '.local', 'share'),
        PACKAGED_DATA_DIRECTORY_NAME
      );
  }
}

export function resolvePersistentDataPath(...segments: string[]): string {
  if (!isPackagedRuntime()) {
    return resolveRuntimePath(...segments);
  }

  return path.join(resolvePackagedDataDirectory(), ...segments);
}

export function resolveProjectRootPath(...segments: string[]): string {
  return path.resolve(__dirname, '..', '..', ...segments);
}

export function findExistingPath(...candidates: string[]): string | null {
  for (const candidate of uniquePaths(candidates)) {
    if (fs.existsSync(candidate)) {
      return candidate;
    }
  }

  return null;
}

export function resolveEnvFilePath(): string {
  if (isPackagedRuntime()) {
    return resolveRuntimePath('.env');
  }

  return findExistingPath(
    resolveRuntimePath('.env'),
    resolveProjectRootPath('.env')
  ) ?? resolveProjectRootPath('.env');
}

export function resolveCertificateDirectory(): string {
  if (isPackagedRuntime()) {
    return resolveRuntimePath('.certs');
  }

  return findExistingPath(
    resolveRuntimePath('.certs'),
    resolveProjectRootPath('.certs')
  ) ?? resolveRuntimePath('.certs');
}
