import { JBoard, readJboardFromFile } from './interpreter/board_formats';

import { Runner } from './interpreter/runner';
import { RuntimeState } from './interpreter/runtime';
import { cli } from '@gobstones/gobstones-core/cli';
import { intl } from './translations';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const packageJSON = require('../package.json');

const runCode = (input: string, initialBoard: JBoard): JBoard => {
    const runner = new Runner();
    const initialState = new RuntimeState();
    runner.parse(input);
    runner.lint();
    if (initialBoard) {
        initialState.load(initialBoard);
    }
    const output = runner.runState(input, initialState);
    return output.state.dump();
};

const showAST = (input: string): string => {
    const runner = new Runner();
    runner.parse(input);
    runner.lint();
    return runner.abstractSyntaxTree.toString();
};

const showVMCode = (input: string): string => {
    const runner = new Runner();
    runner.parse(input);
    runner.lint();
    runner.compile();
    return runner.virtualMachineCode.toString();
};

interface CLIArguments {
    language: string;
    in: string;
    board: string;
    out: string;
    locales?: string;
}

// Read from the package.json in order to retrieve the name and version
const name = (packageJSON.name as string).split('/').slice(-1).pop();
const versionNumber = packageJSON.version;

cli({
    translator: intl,
    texts: {
        name,
        versionNumber,
        help: 'cli.descriptions.help',
        tool: 'cli.descriptions.tool',
        language: 'cli.descriptions.language',
        languageError: 'cli.errors.language',
        version: 'cli.descriptions.version'
    }
})
    .command('run [code]', 'cli.parse.description', (cmd) => {
        cmd.input('cli.descriptions.in', 'cli.errors.file')
            .option('board, b', 'cli.descriptions.board')
            .output('cli.descriptions.out')
            .action((app, _, opts: CLIArguments) => {
                app.outputHelpOnNoArgs();
                const input = app.read();
                const initialBoard = opts.board ? readJboardFromFile(opts.board) : undefined;
                const finalBoard = runCode(input, initialBoard);
                const output = JSON.stringify(finalBoard, undefined, 2);
                app.write(output);
            });
    })
    .command('compile [code]', 'cli.parse.description', (cmd) => {
        cmd.input('cli.descriptions.in', 'cli.errors.file')
            .option('board, b', 'cli.descriptions.board', '')
            .output('cli.descriptions.out')
            .action((app, _, opts: CLIArguments) => {
                app.outputHelpOnNoArgs();
                const input = app.read();
                const bytecode = showVMCode(input);
                const output = JSON.stringify(bytecode, undefined, 2);
                app.write(output);
            });
    })
    .command('parse [code]', 'cli.parse.description', (cmd) => {
        cmd.input('cli.descriptions.in', 'cli.errors.file')
            .option('board, b', 'cli.descriptions.board', '')
            .output('cli.descriptions.out')
            .action((app, _, opts: CLIArguments) => {
                app.outputHelpOnNoArgs();
                const input = app.read();
                const ast = showAST(input);
                const output = JSON.stringify(ast, undefined, 2);
                app.write(output);
            });
    })
    .run();
