import {Command, flags as cmdFlags} from "@oclif/command";
import { readFile } from "fs";
import read from "read";
import {CompilationRequest} from "remote-abap-compiler";
import format from "string-format";

export default class Compile extends Command {
  public static description = "Compile an ABAP source file";

  public static examples = [
    `$ abapc compile -u https://server_name:port_number -u user file.abap
    `,
  ];

  public static flags = {
    client: cmdFlags.string({char: "c", description: "ABAP client", required: true}),
    help: cmdFlags.help({char: "h"}),
    password: cmdFlags.string({char: "p", description: "server password"}),
    url: cmdFlags.string({char: "u", description: "server url", required: true}),
    user: cmdFlags.string({char: "n", description: "username", required: true}),
  };

  public static args = [{name: "file"}];
  private lineOffset: number = 0;

  public async run() {
    const {args, flags} = this.parse(Compile);
    readFile(args.file, "utf8", (err, buffer) => {
      if (err) { throw err; }
      buffer = this.filterOutCommentsAtStartOfFile(buffer);
      this.requirePassword(flags.url, flags.user, flags.client, flags.password,
        (url, user, client, password) => {
          this.connectAndCompile(flags.url, flags.user, flags.client, password, buffer);
      });
    });
  }

  private filterOutCommentsAtStartOfFile(buffer: string): string {
    const newBuffer = buffer.split(/\r?\n/);
    while (newBuffer.length > 0 && newBuffer[0].startsWith("#")) {
      newBuffer.shift();
      this.lineOffset += 1;
    }
    return newBuffer.length > 0 ? newBuffer.join("\n") : "";
  }

  private requirePassword(url: string, user: string, client: string, password: string | undefined,
                          callback: (url: any, user: any, client: any, password: any) => void) {
    if (!password) {
      read({ prompt: "Password: ", silent: true }, (err, pw) => {
        if (!err) {
          callback(url, user, client, pw);
        } else {
          console.log("Cancelled");
        }
      });
    } else {
      callback(url, user, client, password);
    }
  }

  private async connectAndCompile(url: string, user: string, client: string, password: string, code: string) {
    try {
      const req = new CompilationRequest(url, user, client, password);
      const result = await req.compile(code);
      if (result.success) {
        if (result.output) {
          console.log(result.output);
        }
      } else {
        if (result.errors) {
          result.errors.forEach( (error) => {
            console.log(format("Line: {line}, Offset: {offset}, Error: \"{errorMessage}\"", {
              errorMessage: error.errorMessage,
              line: error.line === -1 ? - 1 : (error.line !== undefined ? error.line : 0) + this.lineOffset,
              offset: error.offset,
            }));
          });
        } else {
          console.log(format("Internal error: \"{className}\"", result));
        }
      }
    } catch (error) {
      console.log(error);
      if (error.message !== undefined && error.err !== undefined) {
        console.log(format("HTTP error {err}, Message: \"{message}\"", error));
      } else {
        console.error(error);
      }
    }
  }
}
