import { ServiceBase } from './../../data/service-base';
import { UIInput } from './../../ui/forms/ui-input';
import { Router } from 'aurelia-router';
import { DialogCloseResult, DialogController } from 'aurelia-dialog';
import { ValidationRules, ValidationController } from 'aurelia-validation';
import { inject, InlineViewStrategy, TemplatingEngine, ViewEngine, ViewLocator, ViewResources, Container, autoinject, computedFrom } from 'aurelia-framework';
import { EntityDetailViewModelBase } from '../../vm/detail-view-model-base';
import * as breeze from 'breeze-client';
import { ActionDialogBoxInputParameters } from './../../model/common-model';
import { I18N } from 'aurelia-i18n';
import { KeyboardShortcut } from './../../constants/constants';
import { Config } from '../../config';


export interface ListDialogResultsInterface {
  operation: string;
  selectedEntities: any[];
}

export interface DialogBoxInputParameters {
  message: string;
  title?: string;
  actions?: Array<ActionDialogBoxInputParameters>;
  dialogType?: CustomDialogType;
  editVm?: any;
  input?: string;
  select?: number | Array<number>;
  icon?: string;
  content?: string;
  canSave?: boolean;
  required: boolean;
  isTranslated: boolean;
  service: ServiceBase<breeze.Entity>;
  optionsText: string;
  optionsValue: string;
  isMultiple: boolean;
  position: 'left' | 'right';
  size: string;
}


export enum CustomDialogType {
  Error,
  Question,
  Warning,
  Notification,
  Edit,
  Input,
  RichText,
  Select,
  Custom,
}

@inject(DialogController, ValidationController, Router)
export class DialogBoxViewModel {
  public inputParams: DialogBoxInputParameters;
  public customVM: any;
  public input: string;
  public select: number | Array<number>;
  public inputField: UIInput;

  private config: Config;
  private defaultAction: ActionDialogBoxInputParameters;
  private i18n: I18N;
  public get controller(): DialogController {
    return this._controller;
  }

  @computedFrom('controller.settings.lock')
  public get lock(): boolean {
    return this.controller.settings.lock === true;
  }

  constructor(private _controller: DialogController, private valController: ValidationController, private router: Router, private viewEngine: ViewEngine, private viewResources: ViewResources) {
    this.i18n = Container.instance.get(I18N);
    this.config = Container.instance.get(Config);
    this.defaultAction = {
      label: this.i18n.tr("general.ok", { ns: "common" }),
      title: this.i18n.tr("general.ok", { ns: "common" }),
      theme: 'primary',
      type: 'solid',
      disabled: false,
      fn: () => { this.selectOption("Ok") },
      keyboardShortcut: this.config.globalConfig.keyboardShortcutFwBox ? KeyboardShortcut.Enter : null
    }
  }

  public activate(config: DialogBoxInputParameters) {
    this.inputParams = config;
    this.inputParams.title = config.title || "Application";
    // this.inputParams.options = config.options || ["Ok"];
    this.inputParams.actions = config.actions || (!this.inputParams.canSave ? [this.defaultAction] : []);
    this.inputParams.dialogType = config.dialogType || CustomDialogType.Error;
    this.inputParams.icon = config.icon || "digi-edit";
    this.inputParams.size = config.size || "lg";
    this.input = config.content || null;
    this.select = config.select || (config.isMultiple ? new Array<number>() : null);

    if (this.inputParams.required && (this.inputParams.dialogType == CustomDialogType.Input || this.inputParams.dialogType == CustomDialogType.RichText)) {
      ValidationRules.ensure('input').required().on(this);
    }
  }

  public attached() {
    $(() => {
      if (document.activeElement != null) {
        (document.activeElement as HTMLElement).blur();
      }
      if (this.inputParams.dialogType === CustomDialogType.Input) {
        setTimeout(() => {
          $(this.inputField).find('input').focus();
        }, 100);

      } else {
        ($(document).find('ux-dialog-footer')?.get(0)?.firstElementChild as HTMLUnknownElement)?.focus();
      }
    });
    if (this.inputParams.dialogType == CustomDialogType.Edit) {
      this.handleShortcutsEvent = async (event) => await this.handleShortcuts.call(this, event);
      document.addEventListener("keydown", this.handleShortcutsEvent, false);
    }
  }

  public detached() {
    if (this.inputParams.dialogType == CustomDialogType.Edit) {
      document.removeEventListener("keydown", this.handleShortcutsEvent, false);
    }
  }

  private handleShortcutsEvent: (event: KeyboardEvent) => Promise<any>;

  protected async handleShortcuts(event: KeyboardEvent) {
    if (event.key == KeyboardShortcut.Escape || ((window.navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey) && event.key == "s")) {
      event.stopImmediatePropagation();
      event.preventDefault();
      switch (event.key) {
        case "s":
          await this.saveEntity();
          break;
        case KeyboardShortcut.Escape:
          await this.cancel();
          break;
      }
      return true;
    }
  }

  public async cancel() {
    if ((<EntityDetailViewModelBase<any>>this.customVM?.currentViewModel)?.canDeactivate != null) {
      let result = await (<EntityDetailViewModelBase<any>>this.customVM.currentViewModel).canDeactivate();
      if (result) {
        this.controller.cancel();
      }
    } else {
      this.controller.cancel();
    }

  }

  public async saveEntity() {
    let newEntity = await (<EntityDetailViewModelBase<any>>this.customVM.currentViewModel).saveCurrentEntity();
    if (newEntity != null) {
      this.controller.ok(newEntity);
    }
  }

  public selectOption(dialogResult) {
    if (this.inputParams.dialogType == CustomDialogType.Input || this.inputParams.dialogType == CustomDialogType.RichText) {
      if (this.inputParams.required) {
        this.valController.validate().then((valResult) => {
          if (valResult.valid) {
            this.controller.ok(this.input);
          }
        });
      }
      else {
        this.controller.ok(this.input);
      }
    }
    else if (this.inputParams.dialogType == CustomDialogType.Select) {
      this.controller.ok(this.select);
    }
    else {
      this.controller.ok(dialogResult);
    }
  }

  public async selectAction(action: ActionDialogBoxInputParameters) {
    if (action.fn != null) {
      let promise = null;
      if (typeof action.fn === "function") {
        promise = action.fn(this); //use parameter in MERLIN
      }
      else if (typeof action.fn === "string" && this.customVM.currentViewModel[action.fn] != null) {
        promise = this.customVM.currentViewModel[action.fn]();
      }
      else {
        throw new Error("action.fn must be a function or the name of a function on the dialog's view model");
      }

      if (promise != null) {
        if (typeof promise.then === "function") {
          await (promise as Promise<any>).then((dialogCloseResult?: DialogCloseResult) => {
            if (dialogCloseResult != null && dialogCloseResult.wasCancelled != null) {
              if (!dialogCloseResult.wasCancelled && action.closeDialog) {
                this.controller.ok();
              }
            }
            else if (action.closeDialog) {
              this.controller.ok();
            }
          });
        }
        else {
          if (action.closeDialog) {
            this.controller.ok();
          }
        }
      }
      else {
        if (action.closeDialog) {
          this.controller.ok();
        }
      }
    }
  }

  public goTo(url: string) {
    this.router.navigate(url);
    this.controller.cancel();
  }

  public getViewStrategy(): InlineViewStrategy | string {
    switch (this.inputParams.dialogType) {
      case CustomDialogType.Error:
        return new InlineViewStrategy(this.errorView);
      case CustomDialogType.Question:
        return new InlineViewStrategy(this.questionView);
      case CustomDialogType.Notification:
        return new InlineViewStrategy(this.notificationView);
      case CustomDialogType.Warning:
        return new InlineViewStrategy(this.warningView);
      case CustomDialogType.Edit:
        return new InlineViewStrategy(this.editView);
      case CustomDialogType.Input:
        return new InlineViewStrategy(this.inputView);
      case CustomDialogType.RichText:
        return new InlineViewStrategy(this.richtextView);
      case CustomDialogType.Select:
        return new InlineViewStrategy(this.selectView);
      case CustomDialogType.Custom:
        return new InlineViewStrategy(this.customView);
      default:
        return null;
    }
  }

  private errorView =
    `<template>
        <ux-dialog class="errorBox">
          <ui-dialog-header button-visible.one-time="false == lock" icon="digi-alert-danger" title.bind="inputParams.title"
            button-function.call="controller.cancel()" size="xxl">
          </ui-dialog-header>
      
          <ux-dialog-body>
            <div class="row dialog-box-message">
              <div if.bind="inputParams.isTranslated" class="message" t="[html]\${inputParams.message}"></div>
              <div else class="message" innerhtml.bind="inputParams.message"></div>
            </div>
          </ux-dialog-body>

          <ux-dialog-footer class="right">
            <ui-button repeat.for="action of inputParams.actions" click.delegate="$parent.selectAction(action)"
              icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" class="\${action.class}" size="md"
              ui-theme.bind="action.theme" type.bind="action.type" keyboard-shortcut.bind="action.keyboardShortcut">
            </ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private warningView =
    `<template>
        <ux-dialog class="warningBox">
          <ui-dialog-header button-visible.one-time="false == lock" icon="digi-exclamation-circle" title.bind="inputParams.title"
            button-function.call="controller.cancel()" size="xxl">
          </ui-dialog-header>
      
          <ux-dialog-body>
            <div class="row">
              <div class="col s12">
                <div if.bind="inputParams.isTranslated" class="message" t="[html]\${inputParams.message}"></div>
                <div else class="message" innerhtml.bind="inputParams.message"></div>
              </div>
            </div>
          </ux-dialog-body>

          <ux-dialog-footer class="right">
            <ui-button repeat.for="action of inputParams.actions" click.delegate="$parent.selectAction(action)"
              icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" class="\${action.class}" size="md"
              ui-theme.bind="action.theme" type.bind="action.type" keyboard-shortcut.bind="action.keyboardShortcut">
            </ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private questionView =
    `<template>
        <ux-dialog class="questionBox">
          <ui-dialog-header button-visible.one-time="false == lock" icon="digi-questions" title.bind="inputParams.title"
            button-function.call="controller.cancel()" size="xxl">
          </ui-dialog-header>
      
          <ux-dialog-body>
            <div class="row">
      
              <div class="col s12">
                <div if.bind="inputParams.isTranslated" class="message" t="[html]\${inputParams.message}"></div>
                <div else class="message" innerhtml.bind="inputParams.message"></div>
              </div>
            </div>
          </ux-dialog-body>
      
          <ux-dialog-footer class="right">
            <ui-button repeat.for="action of inputParams.actions" click.delegate="$parent.selectAction(action)"
              icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" class="\${action.class}" size="md"
              ui-theme.bind="action.theme" type.bind="action.type" keyboard-shortcut.bind="action.keyboardShortcut">
            </ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private notificationView =
    `<template>
        <ux-dialog class="notificationBox">
          <ui-dialog-header button-visible.one-time="false == lock" icon="digi-alert-info" title.bind="inputParams.title"
            button-function.call="controller.cancel()" size="xxl">
          </ui-dialog-header>
      
          <ux-dialog-body>
            <div class="row">
              <div class="col s12">
                <div if.bind="inputParams.isTranslated" class="message" t="[html]\${inputParams.message}"></div>
                <div else class="message" innerhtml.bind="inputParams.message"></div>
              </div>
            </div>
          </ux-dialog-body>
          
          <ux-dialog-footer class="right">
            <ui-button repeat.for="action of inputParams.actions" click.delegate="$parent.selectAction(action)"
              icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" class="\${action.class}" size="md"
              ui-theme.bind="action.theme" type.bind="action.type" keyboard-shortcut.bind="action.keyboardShortcut">
            </ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private editView =
    `<template>
        <ux-dialog class.bind="'editDialog ui-dialog-' + inputParams.position + ' ui-dialog-' + inputParams.size">
            <ui-dialog-header icon="\${inputParams.icon}" title.bind="inputParams.title" button-function.call="cancel()" size="xxl">
            </ui-dialog-header>

            <ux-dialog-body>
                <compose view-model.ref="customVM" view-model.bind="inputParams.editVm" model.bind="inputParams" />
            </ux-dialog-body>

            <ux-dialog-footer view-model.bind="inputParams.editVm" class="grid-dialog-footer"
                  if.bind="customVM.currentViewModel.dialogLeftActions.length > 0 || customVM.currentViewModel.dialogRightActions.length > 0 || inputParams.actions.length > 0 || inputParams.canSave">
                <div class="grid-dialog-footer__left">
                    <ui-button repeat.for="action of customVM.currentViewModel.dialogLeftActions" click.delegate="$parent.selectAction(action)" icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" size="md" ui-theme="\${action.theme}" type="\${action.type}"></ui-button>
                </div>
                <div class="grid-dialog-footer__right">
                    <ui-button repeat.for="action of customVM.currentViewModel.dialogRightActions" current.bind="customVM.currentViewModel" disabled.bind="action.disabled" click.delegate="$parent.selectAction(action)" icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" size="md" ui-theme="\${action.theme}" type="\${action.type}"></ui-button>
                    <ui-button repeat.for="action of inputParams.actions" click.delegate="$parent.selectAction(action)" disabled.bind="action.disabled" icon="\${action.icon}" t="[label]\${action.label};[title]\${action.title}" class="\${action.class}" size="md" ui-theme="\${action.theme}" type="\${action.type}"></ui-button>
                    <ui-button if.one-time="inputParams.canSave" disabled.bind="!customVM.currentViewModel.canSave" click.delegate="saveEntity()" icon="digi-save" t="[label]common:general.save" type="solid" size="md" ui-theme="primary"></ui-button>
                </div>
            </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private inputView =
    `<template>
        <ux-dialog class="editDialog ux-dialog-md">
          <ui-dialog-header icon.bind="inputParams.icon" title.bind="inputParams.title" size="xxl" button-visible="true"
            button-function.call="controller.cancel()">
          </ui-dialog-header>
      
          <ux-dialog-body>
            <ui-panel>
              <div class="row">
                <div class="col l12">
                  <ui-field t="[label]\${inputParams.message}">
                    <ui-input value.bind="input & validate" ref="inputField">
                    </ui-input>
                  </ui-field>
                </div>
              </div>
            </ui-panel>
          </ux-dialog-body>
      
          <ux-dialog-footer>
            <ui-button class="right" click.delegate="selectOption()" icon="digi-save" t="[label]common:general.save"
              type="solid" size="md" ui-theme="primary"></ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private richtextView =
    `<template>
        <ux-dialog class="editDialog ux-dialog-md">
          <ui-dialog-header icon.bind="inputParams.icon" title.bind="inputParams.title" size="xxl" button-visible="true" 
            button-function.call="controller.cancel()">
          </ui-dialog-header>

          <ux-dialog-body>
            <ui-panel>
              <div class="row">
                <div class="col l12">
                  <label t="\${inputParams.message}" class="active"></label>
                  <tiny-mce content.two-way="input" class="borderless"></tiny-mce>
                </div>
              </div>
            </ui-panel>
          </ux-dialog-body>

          <ux-dialog-footer>
            <ui-button class="right" click.delegate="selectOption()" icon="digi-save" t="[label]common:general.save"
              type="solid" size="md" ui-theme="primary"></ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private selectView =
    `<template>
        <ux-dialog class="editDialog ux-dialog-md">
          <ui-dialog-header icon.bind="inputParams.icon" title.bind="inputParams.title" size="xxl" button-visible="true" 
            button-function.call="controller.cancel()">
          </ui-dialog-header>
      
          <ux-dialog-body>
            <ui-panel>
              <div class="row">
                <div class="col l12">
                  <ui-field t="[label]\${inputParams.message}">
                    <ui-select if.one-time="inputParams.isMultiple" multiple value.bind="select" data-allow-clear="true"
                      t="[placeholder]general.chooseAnOption" data-source.bind="inputParams.service.gridDataSource"
                      options-text="\${inputParams.optionsText}" filter-properties.bind="inputParams.filterProperties"
                      options-value="\${inputParams.optionsValue}" sort-column="\${inputParams.sortColumn}">
                    </ui-select>
      
                    <ui-select else value.bind="select" data-allow-clear="true" t="[placeholder]general.chooseAnOption"
                      data-source.bind="inputParams.service.gridDataSource" options-text="\${inputParams.optionsText}"
                      filter-properties.bind="inputParams.filterProperties" options-value="\${inputParams.optionsValue}"
                      sort-column="\${inputParams.sortColumn}">
                    </ui-select>
                  </ui-field>
                </div>
              </div>
            </ui-panel>
          </ux-dialog-body>
      
          <ux-dialog-footer> 
            <ui-button class="right" click.delegate="selectOption()" icon="digi-save" t="[label]common:general.save"
              type="solid" size="md" ui-theme="primary"></ui-button>
          </ux-dialog-footer>
        </ux-dialog>
      </template>`;

  private customView =
    `<template>
      <compose view-model.ref="customVM" view-model.bind="inputParams.editVm" model.bind="inputParams" />
    </template>`;
}