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

export type JsPackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';

export function detectJsPackageManager(root: string): JsPackageManager {
  if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';
  if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';
  if (fs.existsSync(path.join(root, 'bun.lockb')) || fs.existsSync(path.join(root, 'bun.lock'))) return 'bun';
  return 'npm';
}

export function installCommandFor(pm: JsPackageManager): { command: string; args: string[] } {
  switch (pm) {
    case 'pnpm':
      return { command: 'pnpm', args: ['install'] };
    case 'yarn':
      return { command: 'yarn', args: ['install'] };
    case 'bun':
      return { command: 'bun', args: ['install'] };
    case 'npm':
    default:
      return { command: 'npm', args: ['install'] };
  }
}

export function runScriptCommandFor(pm: JsPackageManager, script: string, extraArgs: string[] = []): { command: string; args: string[] } {
  switch (pm) {
    case 'pnpm':
      return { command: 'pnpm', args: ['run', script, ...extraArgs] };
    case 'yarn':
      return { command: 'yarn', args: [script, ...extraArgs] };
    case 'bun':
      return { command: 'bun', args: ['run', script, ...extraArgs] };
    case 'npm':
    default:
      return { command: 'npm', args: ['run', script, ...(extraArgs.length ? ['--', ...extraArgs] : [])] };
  }
}

export function addDependencyCommandFor(
  pm: JsPackageManager,
  packages: string[],
  options: { dev?: boolean; remove?: boolean },
): { command: string; args: string[] } {
  if (options.remove) {
    switch (pm) {
      case 'pnpm':
        return { command: 'pnpm', args: ['remove', ...packages] };
      case 'yarn':
        return { command: 'yarn', args: ['remove', ...packages] };
      case 'bun':
        return { command: 'bun', args: ['remove', ...packages] };
      case 'npm':
      default:
        return { command: 'npm', args: ['uninstall', ...packages] };
    }
  }

  switch (pm) {
    case 'pnpm':
      return { command: 'pnpm', args: ['add', ...(options.dev ? ['-D'] : []), ...packages] };
    case 'yarn':
      return { command: 'yarn', args: ['add', ...(options.dev ? ['-D'] : []), ...packages] };
    case 'bun':
      return { command: 'bun', args: ['add', ...(options.dev ? ['-d'] : []), ...packages] };
    case 'npm':
    default:
      return { command: 'npm', args: ['install', ...(options.dev ? ['-D'] : []), ...packages] };
  }
}

export interface PackageJson {
  name?: string;
  scripts?: Record<string, string>;
  dependencies?: Record<string, string>;
  devDependencies?: Record<string, string>;
  workspaces?: string[] | { packages?: string[] };
}

export function readPackageJson(root: string): PackageJson | null {
  const file = path.join(root, 'package.json');
  if (!fs.existsSync(file)) return null;
  try {
    return JSON.parse(fs.readFileSync(file, 'utf8')) as PackageJson;
  } catch {
    return null;
  }
}

export function hasDependency(pkg: PackageJson | null, name: string): boolean {
  if (!pkg) return false;
  return Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
}
