import {Component, OnInit, Output, Inject, OnDestroy, EventEmitter} from '@angular/core';
import 'rxjs/add/operator/toPromise';
import {connectEvt} from '@app/globals';
import {AppService, HttpService, LogService, NavService, SettingService} from '@app/services';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
import {FormControl, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import {SystemUser, TreeNode, Asset} from '@app/model';
import {View} from '@app/model';


@Component({
  selector: 'elements-connect',
  templateUrl: './connect.component.html',
})
export class ElementConnectComponent implements OnInit, OnDestroy {
  @Output() onNewView: EventEmitter<View> = new EventEmitter<View>();

  hasLoginTo = false;

  constructor(private _appSvc: AppService,
              public _dialog: MatDialog,
              public _logger: LogService,
              private settingSvc: SettingService,
              private activatedRoute: ActivatedRoute,
              private _http: HttpService,
  ) {
  }

  ngOnInit(): void {
    connectEvt.asObservable().subscribe(evt => {
      switch (evt.action) {
        case 'asset': {
          this.Connect(evt.node);
          break;
        }
        case 'sftp': {
          this.connectFileManager(evt.node);
          break;
        }
      }
    });
    const loginTo = this._appSvc.getQueryString('login_to');
    const tp = this._appSvc.getQueryString('type') || 'asset';
    if (this.hasLoginTo || !loginTo) {
      return;
    }
    switch (tp) {
      case 'asset':
        this._http.filterMyGrantedAssetsById(loginTo).subscribe(
          nodes => {
            if (nodes.length === 1) {
              this.hasLoginTo = true;
              const node = nodes[0];
              this.Connect(node);
            }
          }
        );
        break;
      case 'remote_app':
        this._http.getMyGrantedRemoteApps(loginTo).subscribe(
          nodes => {
            if (nodes.length === 1) {
              this.hasLoginTo = true;
              const node = nodes[0];
              this.Connect(node);
            }
          }
        );
        break;
    }
  }

  ngOnDestroy(): void {
    connectEvt.unsubscribe();
  }

  Connect(node: TreeNode) {
    switch (node.meta.type) {
      case 'asset':
        this.connectAsset(node);
        break;
      case 'remote_app':
        this.connectRemoteApp(node);
        break;
      case 'database_app':
        this.connectDatabaseApp(node);
        break;
      default:
        alert('Unknown type: ' + node.meta.type);
    }
  }

  async connectAsset(node: TreeNode) {
    const host = node.meta.asset as Asset;
    const systemUsers = await this._http.getMyAssetSystemUsers(host.id).toPromise();
    let sysUser = await this.selectLoginSystemUsers(systemUsers);
    sysUser = await this.manualSetUserAuthLoginIfNeed(sysUser);
    if (sysUser && sysUser.id) {
      this.loginAsset(host, sysUser);
    } else {
      alert('该主机没有授权系统用户');
    }
  }

  async connectDatabaseApp(node: TreeNode) {
    this._logger.debug('Connect remote app: ', node.id);
    const systemUsers = await this._http.getMyDatabaseAppSystemUsers(node.id).toPromise();
    let sysUser = await this.selectLoginSystemUsers(systemUsers);
    sysUser = await this.manualSetUserAuthLoginIfNeed(sysUser);
    if (sysUser && sysUser.id) {
      this.loginDatabaseApp(node, sysUser);
    } else {
      alert('该主机没有授权系统用户');
    }
  }

  selectLoginSystemUsers(systemUsers: Array<SystemUser>): Promise<SystemUser> {
    const systemUserMaxPriority = this.filterMaxPrioritySystemUsers(systemUsers);
    let user: SystemUser;

    if (systemUserMaxPriority.length > 1) {
      return new Promise<SystemUser>(resolve => {
        const dialogRef = this._dialog.open(AssetTreeDialogComponent, {
          height: '250px',
          width: '500px',
          data: {users: systemUserMaxPriority}
        });

        dialogRef.afterClosed().subscribe(result => {
          if (result) {
            for (const i of systemUserMaxPriority) {
              if (i.id.toString() === result.toString()) {
                user = i;
                resolve(user);
              }
            }
          }
          return null;
        });
      });
    } else if (systemUserMaxPriority.length === 1) {
      user = systemUserMaxPriority[0];
      return Promise.resolve(user);
    } else {
      return Promise.resolve(null);
    }
  }

  manualSetUserAuthLoginIfNeed(user: SystemUser): Promise<SystemUser> {
    if (!user || user.login_mode !== 'manual' || user.protocol !== 'rdp' || this.settingSvc.isSkipAllManualPassword()) {
      return Promise.resolve(user);
    }
    user = Object.assign({}, user);
    return new Promise(resolve => {
      const dialogRef = this._dialog.open(ManualPasswordDialogComponent, {
        height: '250px',
        width: '500px',
        data: {username: user.username}
      });
      dialogRef.afterClosed().subscribe(result => {
        if (!result) {
          return resolve(null);
        }
        if (result.skip) {
          return resolve(user);
        }
        user.username = result.username;
        user.password = result.password;
        return resolve(user);
      });
    });

  }


  async connectRemoteApp(node: TreeNode) {
    this._logger.debug('Connect remote app: ', node.id);
    const systemUsers = await this._http.getMyRemoteAppSystemUsers(node.id).toPromise();
    let sysUser = await this.selectLoginSystemUsers(systemUsers);
    sysUser = await this.manualSetUserAuthLoginIfNeed(sysUser);
    if (sysUser && sysUser.id) {
      return this.loginRemoteApp(node, sysUser);
    } else {
      alert('该应用没有授权系统用户');
    }
  }

  loginRemoteApp(node: TreeNode, user: SystemUser) {
    if (node) {
      const view = new View();
      view.nick = node.name;
      view.connected = true;
      view.editable = false;
      view.closed = false;
      view.remoteApp = node.id;
      view.user = user;
      view.type = 'rdp';
      this.onNewView.emit(view);
    }
  }
  loginDatabaseApp(node: TreeNode, user: SystemUser) {
    if (node) {
      const view = new View();
      view.host = node;
      view.nick = node.name;
      view.connected = true;
      view.editable = false;
      view.closed = false;
      view.DatabaseApp = node.id;
      view.user = user;
      view.type = 'database';
      this.onNewView.emit(view);
    }
  }

  connectFileManager(node: TreeNode) {
    const host = node.meta.asset as Asset;
    if (host) {
      const view = new View();
      view.nick = '[FILE] ' + host.hostname;
      view.connected = true;
      view.editable = false;
      view.closed = false;
      view.host = host;
      view.type = 'sftp';
      this.onNewView.emit(view);
      // jQuery('.tabs').animate({'scrollLeft': 150 * id}, 400);
    }
  }

  connectTerminal(node: TreeNode) {
    this.Connect(node);
  }


  loginAsset(host: Asset, user: SystemUser) {
    if (user) {
      const view = new View();
      view.nick = host.hostname;
      view.connected = true;
      view.editable = false;
      view.closed = false;
      view.host = host;
      view.user = user;
      if (user.protocol === 'ssh' || user.protocol === 'telnet') {
        view.type = 'ssh';
      } else if (user.protocol === 'rdp' || user.protocol === 'vnc') {
        view.type = 'rdp';
      }
      this.onNewView.emit(view);
    }
  }

  filterMaxPrioritySystemUsers(sysUsers: Array<SystemUser>): Array<SystemUser> {
    const priorityAll: Array<number> = sysUsers.map(s => s.priority);
    const maxPriority = Math.max(...priorityAll);
    return sysUsers.filter(s => s.priority === maxPriority);
  }
}


@Component({
  selector: 'elements-asset-tree-dialog',
  templateUrl: 'dialog.html',
})
export class AssetTreeDialogComponent implements OnInit {
  UserSelectControl = new FormControl('', [Validators.required]);
  selected: any;

  constructor(public dialogRef: MatDialogRef<AssetTreeDialogComponent>,
              @Inject(MAT_DIALOG_DATA) public data: any,
              private _logger: LogService) {
  }

  ngOnInit() {
    this.selected = this.data.users[0].id;
    this.UserSelectControl.setValue(this.selected);
    // this._logger.debug(this.UserSelectControl);
  }

  onNoClick(): void {
    this.dialogRef.close();
  }

  compareFn: ((f1: any, f2: any) => boolean) | null = this.compareByValue;

  compareByValue(f1: any, f2: any) {
    return f1 && f2 && f1.value === f2.value;
  }
}

@Component({
  selector: 'elements-manual-password-dialog',
  templateUrl: 'manual-password-dialog.html',
})
export class ManualPasswordDialogComponent implements OnInit {
  constructor(@Inject(MAT_DIALOG_DATA) public data: any,
              public dialogRef: MatDialogRef<ManualPasswordDialogComponent>) {
  }

  onSkip() {
    this.data.skip = true;
    this.dialogRef.close(this.data);
  }

  onSkipAll() {
    this.data.skipAll = true;
    this.dialogRef.close(this.data);
  }

  onNoClick() {
    this.dialogRef.close();
  }

  onEnter() {
    this.dialogRef.close(this.data);
  }

  ngOnInit(): void {
  }
}