import { IBaseFleioObjectModel } from '@fleio-api/base-model/base-fleio-object.model';
import { Observable, of } from 'rxjs';
import { IAction, PostExecutionCallback } from '../interfaces/actions/action';
import { IIcon } from '../../common/interfaces/icon';
import { delay, map } from 'rxjs/operators';
import { NotificationService } from '@shared/ui-api/notification.service';
import { IActionResult } from '../interfaces/actions/action-result';
import { IActionConfirmOptions } from '../interfaces/actions/action-confirm-options';
import { RefreshService } from '@shared/ui-api/refresh.service';
import { ActionTypes } from '@objects-view/actions/action-types';
import { IYesNoDialogResult } from '@shared/ui-api/interfaces/yes-no-dialog-result';
import { IYesNoDialogData } from '@shared/ui-api/interfaces/yes-no-dialog-data';

export class BaseAction implements IAction {
  object: IBaseFleioObjectModel;
  icon: IIcon;
  name: string;
  internalName: string;
  tooltip: string;
  primary: boolean;
  type: ActionTypes;

  displayMessages = true;
  confirmOptions?: IActionConfirmOptions;

  disabled: boolean;
  ignoreFormInvalidity: boolean = false;
  isRunning: boolean;
  noPermissions: boolean;
  noPermissionsAutomaticTooltip = true;
  featureName: string;
  refreshAfterExecute = true;
  redirectAfterExecute = false;
  redirectUrl: string;
  redirectUrlFragment: string = null;
  redirectQueryParams: Record<string, any> = null;
  propagateQueryParams: string[] = ['search', 'filtering'];
  postExecuteCallback?: PostExecutionCallback;

  notificationService: NotificationService;
  mouseEvent: MouseEvent;

  constructor(init?: Partial<BaseAction>) {
    Object.assign(this, init);
    if (!this.tooltip) {
      if (this.noPermissions) {
        this.tooltip = $localize`You don't have permissions to perform this action`;
      }
      if (this.disabled) {
        this.tooltip = $localize`This action is disabled`;
      }
    } else {
      if (this.noPermissions && this.noPermissionsAutomaticTooltip) {
        this.tooltip = this.tooltip + $localize` - no permissions`;
      }
    }
  }

  executeImpl(dialogResult: IYesNoDialogResult): Observable<IActionResult> {
    console.warn('Base object action executeImpl method invoked, ' +
      'override this in your derived classes. Dialog result:');
    console.warn(dialogResult);
    return of({
      success: false,
      message: $localize`Base object action execute method invoked.`,
    }).pipe(delay(1000));
  }

  execute(
    notificationService: NotificationService, refreshService: RefreshService,
    event?: MouseEvent, postExecuteCallback?: PostExecutionCallback,
  ) {
    this.mouseEvent = event;
    this.mouseEvent.preventDefault();
    this.isRunning = true;
    this.notificationService = notificationService;
    let dialogResult$: Observable<IYesNoDialogResult>;
    if (this.confirmOptions?.confirm) {
      const yesNoData: IYesNoDialogData = {...this.confirmOptions};
      yesNoData.yesAction = dialogResult => { return this.executeImpl(dialogResult); };
      dialogResult$ = notificationService.confirmDialog(yesNoData);
    } else {
      dialogResult$ = this.executeImpl({
        button: 'yes'
      }).pipe(map(actionResult=> {
        return {
          button: 'yes',
          actionResult: actionResult,
        }
      }));
    }

    dialogResult$.subscribe(dialogResult => {
      if (dialogResult?.button === 'yes') {
        refreshService.resetPageChanged();
        {
          if (this.displayMessages && dialogResult.actionResult?.message) {
            notificationService.showMessage(dialogResult.actionResult.message);
          }
          const activePostExecuteCallback = postExecuteCallback || this.postExecuteCallback;
          if (activePostExecuteCallback) {
            activePostExecuteCallback(this, dialogResult.actionResult);
          }
          if (dialogResult.actionResult?.success === false) {
            // no need to refresh or redirect on failure
            return;
          } else {
            if (this.refreshAfterExecute) {
              refreshService.refresh(null, true);
            }
            if (this.redirectAfterExecute) {
              refreshService.redirect(
                this.redirectUrl,
                this.propagateQueryParams,
                true,
                this.redirectQueryParams,
                this.redirectUrlFragment,
              );
            }
          }
        }
      }
    }).add(()=>{
      this.isRunning = false;
    });
  }
}
