import { resolve } from 'path';
import { log } from '../common/log';
import { findFile } from '../common/io';
import { runCommand } from '../common/scripts';
import { MemoryStream } from '../common/MemoryStream';

// Helpers:

async function runYarnProcess(args: Array<string>, target: string, output?: MemoryStream) {
  log('generalDebug_0003', 'Starting the Yarn Classic process ...');
  const cwd = resolve(process.cwd(), target);
  return await runCommand('yarn', args, cwd, output);
}

async function tryRunYarnProcess(args: Array<string>, target: string, output: MemoryStream) {
  try {
    return await runYarnProcess(args, target, output);
  } catch (err) {
    log('generalInfo_0000', output.value || `yarn failed due to ${err}`);
    throw err;
  }
}

function convert(flags: Array<string>) {
  return flags.map((flag) => {
    switch (flag) {
      case '--save-exact':
        return '--exact';
      case '--save-dev':
        return '--dev';
      case '--no-save':
        // unfortunately no (https://github.com/yarnpkg/yarn/issues/1743)
        return '';
      default:
        return flag;
    }
  });
}

// Client interface functions:

export async function installDependencies(target = '.', ...flags: Array<string>) {
  const ms = new MemoryStream();
  await tryRunYarnProcess(['install', ...convert(flags)], target, ms);
  log('generalDebug_0003', `Yarn Classic install dependencies result: ${ms.value}`);
  return ms.value;
}

export async function uninstallPackage(packageRef: string, target = '.', ...flags: Array<string>) {
  const ms = new MemoryStream();
  await tryRunYarnProcess(['remove', packageRef, ...convert(flags)], target, ms);
  log('generalDebug_0003', `Yarn Classic remove package result: ${ms.value}`);
  return ms.value;
}

export async function installPackage(packageRef: string, target = '.', ...flags: Array<string>) {
  const ms = new MemoryStream();
  await tryRunYarnProcess(['add', packageRef, ...convert(flags)], target, ms);
  log('generalDebug_0003', `Yarn Classic add package result: ${ms.value}`);
  return ms.value;
}

export async function detectClient(root: string, stopDir = resolve(root, '/')) {
  return !!(await findFile(root, 'yarn.lock', stopDir));
}

export async function initProject(projectName: string, target: string) {}

export async function isProject(root: string, packageRef: string) {
  const details = await listProjects(root);

  if (typeof details === 'object') {
    return typeof details?.[packageRef]?.location === 'string';
  }

  return false;
}

// Functions to exclusively use from yarn client:

export async function listProjects(target: string) {
  const ms = new MemoryStream();

  try {
    await runYarnProcess(['workspaces', 'info'], target, ms);
    log('generalDebug_0003', `yarn workspaces result: ${ms.value}`);
    return JSON.parse(ms.value);
  } catch (e) {
    log('generalDebug_0003', `yarn workspaces error: ${e}`);
    return {};
  }
}
