import * as fs from 'node:fs';
import * as path from 'node:path';

export interface YomitanExtensionPathOptions {
  explicitPath?: string;
  cwd?: string;
  moduleDir?: string;
  resourcesPath?: string;
  userDataPath?: string;
}

function pushUnique(values: string[], candidate: string | null | undefined): void {
  if (!candidate || values.includes(candidate)) {
    return;
  }
  values.push(candidate);
}

export function getYomitanExtensionSearchPaths(
  options: YomitanExtensionPathOptions = {},
): string[] {
  const searchPaths: string[] = [];

  pushUnique(searchPaths, options.explicitPath ? path.resolve(options.explicitPath) : null);
  pushUnique(searchPaths, options.cwd ? path.resolve(options.cwd, 'build', 'yomitan') : null);
  pushUnique(
    searchPaths,
    options.moduleDir
      ? path.resolve(options.moduleDir, '..', '..', '..', 'build', 'yomitan')
      : null,
  );
  pushUnique(
    searchPaths,
    options.resourcesPath ? path.join(options.resourcesPath, 'yomitan') : null,
  );
  pushUnique(searchPaths, '/usr/share/SubMiner/yomitan');
  pushUnique(searchPaths, options.userDataPath ? path.join(options.userDataPath, 'yomitan') : null);

  return searchPaths;
}

export function resolveExistingYomitanExtensionPath(
  searchPaths: string[],
  existsSync: (path: string) => boolean = fs.existsSync,
): string | null {
  for (const candidate of searchPaths) {
    if (existsSync(path.join(candidate, 'manifest.json'))) {
      return candidate;
    }
  }

  return null;
}

export function resolveYomitanExtensionPath(
  options: YomitanExtensionPathOptions = {},
  existsSync: (path: string) => boolean = fs.existsSync,
): string | null {
  return resolveExistingYomitanExtensionPath(getYomitanExtensionSearchPaths(options), existsSync);
}

export function resolveExternalYomitanExtensionPath(
  externalProfilePath: string,
  existsSync: (path: string) => boolean = fs.existsSync,
): string | null {
  const normalizedProfilePath = externalProfilePath.trim();
  if (!normalizedProfilePath) {
    return null;
  }

  const candidate = path.join(normalizedProfilePath, 'extensions', 'yomitan');
  const fallbackCandidate = path.join(path.resolve(normalizedProfilePath), 'extensions', 'yomitan');

  const candidates = candidate === fallbackCandidate ? [candidate] : [candidate, fallbackCandidate];
  for (const root of candidates) {
    if (existsSync(path.join(root, 'manifest.json'))) {
      return root;
    }
  }

  return null;
}
