import { IPermissionsModel } from '@fleio-api/base-model/IPermissionsModel';
import { IIcon } from '@shared/ui/common/interfaces/icon';
import { ITitle } from '@objects-view/interfaces/card-data/card-title';
import { IObjectStatus, StatusType, StatusValue } from '@objects-view/interfaces/object-status';
import { ObjectUIServiceBase } from '@objects-view/object-ui-service-base';
import { IAction } from '@objects-view/interfaces/actions/action';
import { RouterLinkAction } from '@objects-view/actions/router-link-action';
import { Router } from '@angular/router';
import { ConfigService } from '@shared/config/config.service';
import { IDataField } from '@objects-view/interfaces/card-data/data-field';
import { ApiCallAction, CallType } from '@objects-view/actions/api-call-action';
import { IDetailsTab } from '@objects-view/interfaces/details/details-tab';
import { CallbackAction } from '@objects-view/actions/callback-action';
import { VolumesApiService } from '@fleio-api/openstack/volume/volumes-api.service';
import { IVolumeModel } from '@fleio-api/openstack/model/volume.model';
import {
  VolumeDetailsOverviewComponent
} from '@shared/common-tabs/openstack/volumes/volume-details-overview/volume-details-overview.component';
import {
  VolumeEditFormComponent
} from '@shared/common-tabs/openstack/volumes/volume-edit-form/volume-edit-form.component';
import { catchError, map } from 'rxjs/operators';
import { IActionResult } from '@objects-view/interfaces/actions/action-result';
import { MatDialog } from '@angular/material/dialog';
import { VolumeRenameComponent } from '@shared/common-dialogs/openstack/volumes/volume-rename/volume-rename.component';
import { VolumeExtendComponent } from '@shared/common-dialogs/openstack/volumes/volume-extend/volume-extend.component';
import { FleioObjectsList } from '@fleio-api/fleio-objects-list';
import { IVolumeBackupModel } from '@fleio-api/openstack/model/volume-backup.model';
import {
  VolumeDetailsBackupsComponent
} from '@shared/common-tabs/openstack/volumes/volume-details-backups/volume-details-backups.component';
import {
  VolumeDetailsSnapshotsComponent
} from '@shared/common-tabs/openstack/volumes/volume-details-snapshots/volume-details-snapshots.component';
import {
  RevertVolumeToSnapshotDialogComponent
} from '@shared/common-dialogs/openstack/volumes/revert-volume-to-snapshot-dialog/revert-volume-to-snapshot-dialog.component';
import {
  VolumeUploadToImageFormComponent
} from '@shared/common-tabs/openstack/volumes/volume-upload-to-image-form/volume-upload-to-image-form.component';
import { of } from 'rxjs';

export class VolumeUiService extends ObjectUIServiceBase<IVolumeModel> {
  constructor(
    volume: IVolumeModel, permissions: IPermissionsModel, state: string,
    private router: Router, private config: ConfigService, private volumesApiService: VolumesApiService,
    private matDialog: MatDialog,
  ) {
    super(volume, permissions, state);
  }

  getIcon(): IIcon {
    return null;
  }

  getStatus(): IObjectStatus {
    switch (this.object.status) {
      case 'error':
      case 'error_restoring':
        return {
          value: StatusValue.Error,
          type: StatusType.Defined,
        };
      case 'deleting':
        return {
          value: StatusValue.Deleted,
          type: StatusType.Changing,
        };
      case 'in-use':
        return {
          value: StatusValue.Warning,
          type: StatusType.Defined,
        };
      case 'extending':
      case 'attaching':
      case 'creating':
      case 'reverting':
      case 'restoring-backup':
        return {
          value: StatusValue.Pending,
          type: StatusType.Changing,
        };
      case 'available':
      default:
        return {
          value: StatusValue.Enabled,
          type: StatusType.Defined,
        };
    }
  }

  getTitle(): ITitle {
    switch (this.state) {
      case 'edit':
        return {
          text: $localize`Edit volume ${this.object.name || this.object.id}`,
        };

      case 'create':
        return {
          text: $localize`Create new volume`,
        };

      default:
        return {
          text: `${this.object.name || this.object.id}`,
          subText: this.object.status.toLocaleUpperCase(),
        };
    }
  }

  getActions(): IAction[] {
    const actions: IAction[] = [];

    actions.push(new CallbackAction(
      {
        object: this.object,
        icon: {name: 'edit'},
        tooltip: $localize`Rename volume`,
        name: $localize`Rename`,
        noPermissions: !this.permissions['volumes.rename'],
        callback: () => this.matDialog.open(
          VolumeRenameComponent, {
            data: {volume: this.object},
            autoFocus: false,
          }).afterClosed().pipe(map(result => {
          if (result === false) {
            return;
          }
          return {message: result} as IActionResult;
        }))
      }
    ));

    actions.push(new CallbackAction(
      {
        object: this.object,
        icon: {name: 'resize', class: 'fl-icons'},
        tooltip: $localize`Extend volume`,
        name: $localize`Extend`,
        disabled: ['in-use', 'available'].indexOf(this.object.status) < 0,
        noPermissions: !this.permissions['volumes.extend'],
        callback: () => this.matDialog.open(
          VolumeExtendComponent, {
            data: {volume: this.object},
            autoFocus: false,
          }).afterClosed().pipe(map(result => {
          if (result === false) {
            return;
          }
          return {message: result} as IActionResult;
        }))
      }
    ));

    actions.push(new CallbackAction(
      {
        object: this.object,
        icon: {name: 'settings_power'},
        tooltip: $localize`Edit bootable status`,
        name: $localize`Edit bootable status`,
        displayMessages: true,
        confirmOptions: {
          confirm: true,
          title: $localize`Change volume ${this.object.name || this.object.id} bootable status`,
          message: null,
          yesButtonName: $localize`Change bootable flag`,
          noButtonName: $localize`Cancel`,
          flags: [{
            id: 'is_bootable',
            message: $localize`Is bootable`,
            selected: this.object.bootable,
          }],
        },
        callback: (action, result) => {
          if (result?.button === 'yes') {
            const isBootable = !!result.flags?.is_bootable;
            return this.volumesApiService.changeBootableStatus(
              this.object.id, isBootable
            ).pipe(map(response => {
              return {
                success: true,
                message: response.detail,
              } as IActionResult;
            }), catchError((error, caught) => {
              return of({success: false, message: error.error.detail} as IActionResult)
            }));
          } else {
            return of({success: false} as IActionResult);
          }
        },
        refreshAfterExecute: true,
        noPermissions: !this.permissions['volumes.change_bootable_status'],
      }
    ));

    actions.push(new CallbackAction(
      {
        object: this.object,
        icon: {name: 'redo'},
        tooltip: $localize`Revert to snapshot`,
        name: $localize`Revert to snapshot`,
        callback: () => this.matDialog.open(
          RevertVolumeToSnapshotDialogComponent, {
            data: {
              volume: this.object,
            },
            autoFocus: false,
          }).afterClosed().pipe(map(result => {
          if (result === false) {
            return;
          }
          return {message: result} as IActionResult;
        })),
        refreshAfterExecute: true,
        disabled: this.object.status !== 'available',
        noPermissions: !this.permissions['volumes.revert_to_snapshot'],
      }
    ));

    actions.push(
      new RouterLinkAction({
          name: $localize`Upload to image`,
          tooltip: $localize`Upload to image`,
          icon: {name: 'images', class: 'fl-icons'},
          router: this.router,
          routerUrl: this.config.getPanelUrl(`openstack/volumes/${this.object.id}/upload-to-image`),
          noPermissions: !this.permissions['volumes.upload_to_image'],
        }
      )
    );

    actions.push(new ApiCallAction(
      {
        object: this.object,
        icon: {name: 'delete'},
        name: $localize`Delete`,
        tooltip: $localize`Delete`,
        confirmOptions: {
          confirm: true,
          title: $localize`Delete volume`,
          message: $localize`Are you sure you want to delete volume ${this.object.name || this.object.id}?`,
        },
        successMessage: $localize`Volume delete queued`,
        errorMessage: $localize`Failed to delete volume`,
        apiService: this.volumesApiService,
        callType: CallType.Delete,
        refreshAfterExecute: false,
        redirectAfterExecute: true,
        redirectUrl: this.config.getPanelUrl('openstack/volumes'),
        noPermissions: !this.permissions['volumes.destroy'],
      }
    ));

    return actions;
  }

  getDetailsActions(): IAction[] {
    const actions = [];

    switch (this.state) {
      case 'create':
        actions.push(new RouterLinkAction({
            name: $localize`Cancel`,
            routerUrl: this.config.getPrevUrl(`openstack/volumes`),
            router: this.router,
          }
        ));
        actions.push(new CallbackAction({name: $localize`Create`}));
        break;
      case 'upload-to-image':
        actions.push(new RouterLinkAction({
            name: $localize`Cancel`,
            routerUrl: this.config.getPrevUrl(`openstack/volumes`),
            router: this.router,
          }
        ));
        actions.push(new CallbackAction({name: $localize`Upload`}));
        break;
      case 'edit':
        actions.push(new RouterLinkAction({
            name: $localize`Cancel`,
            routerUrl: this.config.getPrevUrl(`openstack/volumes`),
            router: this.router,
          }
        ));
        actions.push(new CallbackAction({name: $localize`Save`}));
        break;
      default:
        break;
    }

    return actions;
  }

  getDetailsLink(): string {
    return this.config.getPanelUrl(`openstack/volumes/${this.object.id}`);
  }

  getCardFields(): IDataField[] {
    return [
      {
        value: $localize`${this.object.size} GB, ${this.object.region}`
      },
      {
        name: $localize`Type`,
        value: this.object.type,
      },
      {
        name: $localize`Availability zone`,
        value: this.object.availability_zone,
      }
    ];
  }

  getTabs(additionalObjects?: {
    backups: FleioObjectsList<IVolumeBackupModel>;
    snapshots: FleioObjectsList<IVolumeBackupModel>;
  }): IDetailsTab[] {
    switch (this.state) {
      case 'details':
        return [
          {
            tabName: $localize`Overview`,
            tabIdentifier: 'overview',
            component: VolumeDetailsOverviewComponent,
          },
          {
            tabName: additionalObjects.backups ? $localize`Backups (${additionalObjects.backups.objects.length})` : $localize`Backups`,
            tabIdentifier: 'backups',
            component: VolumeDetailsBackupsComponent,
            featureName: 'openstack.volumes.backups',
          },
          {
            tabName: additionalObjects.snapshots ?
              $localize`Snapshots (${additionalObjects.snapshots.objects.length})` : $localize`Snapshots`,
            tabIdentifier: 'snapshots',
            component: VolumeDetailsSnapshotsComponent,
            featureName: 'openstack.volumes.snapshots'
          },
        ];
      case 'create':
        return [
          {
            tabName: $localize`Create`,
            tabIdentifier: 'create',
            component: VolumeEditFormComponent,
          },
        ];
      case 'upload-to-image':
        return [
          {
            tabName: $localize`Upload to image`,
            tabIdentifier: 'upload-to-image',
            component: VolumeUploadToImageFormComponent,
          },
        ];
    }
  }

  getCardTags(): string[] {
    return [];
  }

  getObjectDetailsRefreshInterval(): number {
    switch (this.state) {
      case 'details':
        if (['extending', 'attaching'].indexOf(this.object.status) < 0) {
          return this.config.getDefaultRefreshInterval();
        } else {
          return this.config.getDefaultRefreshInterval(true);
        }
      default:
        return null;
    }
  }
}
