import { RendererApi } from '../common/rendererApi';
import * as fs from 'fs';
import * as path from 'path';
import * as child_process from 'child_process';
import * as readline from 'readline';
import * as os from 'os';

const compiler = process.env.CXX ? process.env.CXX : 'g++';
// 一時ディレクトリに関する情報
const isDevelopment = process.env.NODE_ENV === 'development';
const isWindows = process.platform === 'win32';
const tmpDirName = isDevelopment ? 'tmp' : 'cq-interface-blockly';
const tmpRoot = isDevelopment ? tmpDirName : path.join(os.tmpdir(), tmpDirName);

export async function saveTextFile(rapi: RendererApi, filepath: string, contents: string): Promise<boolean> {
  try {
    const dirname = path.dirname(filepath);
    if (dirname != '' && dirname != '.' && !fs.existsSync(dirname)) {
      await fs.promises.mkdir(dirname, { recursive: true });
    }
    await fs.promises.writeFile(filepath, contents);
    return true;
  } catch (e) {
    const msg = `Error: ${e}`;
    rapi.err(msg);
    return false;
  }
}

export async function readTextFile(rapi: RendererApi, filepath: string): Promise<string | null> {
  try {
    return await fs.promises.readFile(filepath, 'utf8');
  } catch (e) {
    const msg = `Error: ${e}`;
    rapi.err(msg);
    return null;
  }
}

export async function makeTmpDirectory(): Promise<string> {
  if (!fs.existsSync(tmpRoot)) {
    await fs.promises.mkdir(tmpRoot, { recursive: true });
  }
  const dir = await fs.promises.mkdtemp(path.join(tmpRoot, 'tmp'));
  return dir;
}

/**
 * makeTmpDirectoryで作成したディレクトリを全て削除します。
 * プロセスの終了フックなどで使うことを想定しています。
 */
export function deleteAllTmpDirectoriesSync() {
  if (fs.existsSync(tmpRoot)) {
    if (isWindows) {
      child_process.execSync(`rmdir /s /q "${tmpRoot}"`);
    } else {
      child_process.execSync(`rm -rf '${tmpRoot}'`);
    }
  }
}

export function compile(rapi: RendererApi, filepath: string, output: string): Promise<boolean> {
  return new Promise((resolve, reject) => {
    const args = ['--std=c++14', '-o', output, filepath];
    rapi.cmd(compiler, args);
    const child = child_process.spawn(compiler, args);
    child.on('error', e => {
      rapi.err('Fail to compile : ' + e.message);
      reject(e.message);
    });

    readline
      .createInterface({
        input: child.stdout,
        terminal: false,
      })
      .on('line', data => {
        rapi.writeLine(data);
      });

    readline
      .createInterface({
        input: child.stderr,
        terminal: false,
      })
      .on('line', data => {
        rapi.writeLineErr(data);
      });
    child.on('close', code => resolve(code == 0));
  });
}

export function exec(rapi: RendererApi, exec: string): Promise<number> {
  return new Promise(resolve => {
    rapi.cmd(exec);
    const child = child_process.spawn(exec);
    readline
      .createInterface({
        input: child.stdout,
        terminal: false,
      })
      .on('line', data => {
        const i = data.indexOf(':');
        if (i < 0) {
          rapi.writeLine(data);
          return;
        }
        const value = data.substr(i + 1);
        switch(data.substr(0, i)) {
          case "ON": rapi.setHighlight(value, true);break;
          case "OFF": rapi.setHighlight(value, false);break;
          case "MSG": rapi.writeLine(value);break;
          default: console.log("Unknown", data);break;
        }
      });
    readline
      .createInterface({
        input: child.stderr,
        terminal: false,
      })
      .on('line', data => {
        rapi.writeLineErr(data);
      });
    child.on('close', code => resolve(code == null ? 0 : code));
  });
}
