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 { 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 { FleioObjectsList } from '@fleio-api/fleio-objects-list';
import { IVolumeBackupModel } from '@fleio-api/openstack/model/volume-backup.model';
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 { EntityAuditLogComponent } from '../../common-components/entity-audit-log/entity-audit-log.component';
import { of } from 'rxjs';

export class VolumeUiService extends ObjectUIServiceBase<IVolumeModel> {
  private readonly router: Router;
  private readonly config: ConfigService;
  private readonly volumesApiService: VolumesApiService;
  private readonly matDialog: MatDialog;


  constructor(
    volume: IVolumeModel, permissions: IPermissionsModel, state: string,
    router: Router, config: ConfigService, volumesApiService: VolumesApiService, matDialog: MatDialog,
  ) {
    super(volume, permissions, state);
    this.matDialog = matDialog;
    this.router = router;
    this.config = config;
    this.volumesApiService = volumesApiService;
  }

  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, check logs for details`,
        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: '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[] {
    let firstRow = $localize`${this.object.size} GB, ${this.object.region}`;
    if (this.object.availability_zone) {
      firstRow += `, ${this.object.availability_zone}`;
    }
    return [
      {
        value: firstRow
      },
      {
        name: $localize`Client`,
        value: this.object.client ? this.object.client.display : $localize`n/a`,
      },
      {
        value: this.object.type,
      }
    ];
  }

  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'
          },
          {
            tabName: $localize`Audit log`,
            tabIdentifier: 'audit-log',
            component: EntityAuditLogComponent,
            featureName: 'utils.activitylog',
            data: {
              entity_type: 'volume'
            }
          }
        ];
      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;
    }
  }
}
