/*
 * Copyright (C) Sapphirecode - All Rights Reserved
 * This file is part of console-app which is released under MIT.
 * See file 'LICENSE' for full license details.
 * Created by Timo Hocker <timo@scode.ovh>, May 2020
 */

/* eslint-disable no-console */
/* eslint-disable no-process-exit */
import { Confirm, Input, List, AutoComplete } from 'enquirer';
import { OptionProcess, Option } from '../Option';
import { ErrorCallback } from '../Types/ErrorCallback';
import { OptionSource } from './OptionSource';

export class InteractiveSource extends OptionSource {
  private _exit_on_interrupt: boolean;

  public constructor (
    exit_on_interrupt: boolean,
    error_callback?:ErrorCallback
  ) {
    super (error_callback);
    this._exit_on_interrupt = exit_on_interrupt;
  }

  private get_message (opt: Option): string {
    return typeof opt.message === 'undefined'
      ? `input ${opt.name}`
      : opt.message;
  }

  private async prompt (opt: OptionProcess): Promise<void> {
    if (opt.filled)
      return;
    let value = null;
    if (
      opt.type === 'string'
      || opt.type === 'file'
      || opt.type === 'folder'
      || opt.type === 'path'
      || opt.type === 'number'
    ) {
      if (typeof opt.preset === 'undefined') {
        value = await new Input ({
          message: this.get_message (opt),
          default: opt.default
        })
          .run ();
      }
      else {
        value = await new AutoComplete ({
          message: this.get_message (opt),
          default: opt.default,
          choices: opt.preset,
          limit:   10
        })
          .run ();
      }
    }
    if (
      opt.type === 'boolean'
    ) {
      value = await new Confirm ({
        message: this.get_message (opt),
        default: opt.default
      })
        .run ();
    }
    if (opt.type === 'array') {
      value = await new List ({
        message: this.get_message (opt),
        default: opt.default
      })
        .run ();
    }
    if (value === null)
      return;

    await this.assign_arg (opt, value);
  }

  public async parse (options: OptionProcess[]): Promise<void> {
    for (const opt of options) {
      while (!opt.filled) {
        // eslint-disable-next-line no-await-in-loop
        await this.prompt (opt)
          .catch ((e) => {
            if (this._exit_on_interrupt)
              process.exit (0);
            throw e;
          });
        if (!opt.filled)
          console.log (opt.error || 'input was invalid');
      }
    }
  }
}