import { Location } from '@angular/common';
import {
  Directive,
  Input,
  OnInit,
} from '@angular/core';
import {
  ActivatedRoute,
  Data,
  Params,
  Router,
} from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import {
  combineLatest,
  Observable,
} from 'rxjs';
import {
  map,
  switchMap,
  take,
} from 'rxjs/operators';

import { RemoteData } from '../core/data/remote-data';
import { RequestService } from '../core/data/request.service';
import { RouteService } from '../core/services/route.service';
import { Item } from '../core/shared/item.model';
import {
  getAllSucceededRemoteData,
  getRemoteDataPayload,
} from '../core/shared/operators';
import { WorkflowItem } from '../core/submission/models/workflowitem.model';
import { WorkflowItemDataService } from '../core/submission/workflowitem-data.service';
import { isEmpty } from '../shared/empty.util';
import { NotificationsService } from '../shared/notifications/notifications.service';

/**
 * Abstract component representing a page to perform an action on a workflow item
 */
@Directive({
  // eslint-disable-next-line @angular-eslint/directive-selector
  selector: 'ds-workflowitem-action-page',
  standalone: true,
})
export abstract class WorkflowItemActionPageDirective implements OnInit {

  @Input() type: string;

  public wfi$: Observable<WorkflowItem>;
  public item$: Observable<Item>;
  protected previousQueryParameters?: Params;

  constructor(protected route: ActivatedRoute,
              protected workflowItemService: WorkflowItemDataService,
              protected router: Router,
              protected routeService: RouteService,
              protected notificationsService: NotificationsService,
              protected translationService: TranslateService,
              protected requestService: RequestService,
              protected location: Location,
  ) {
  }

  /**
   * Sets up the type, workflow item and its item object
   */
  ngOnInit() {
    this.type = this.getType();
    this.wfi$ = this.route.data.pipe(map((data: Data) => data.wfi as RemoteData<WorkflowItem>), getRemoteDataPayload());
    this.item$ = this.wfi$.pipe(switchMap((wfi: WorkflowItem) => (wfi.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload())));
    this.previousQueryParameters = (this.location.getState() as { [key: string]: any })?.previousQueryParams;
  }

  /**
   * Performs the action and shows a notification based on the outcome of the action
   */
  performAction() {
    combineLatest([this.wfi$, this.requestService.removeByHrefSubstring('/discover')]).pipe(
      take(1),
      switchMap(([wfi]) => this.sendRequest(wfi.id)),
    ).subscribe((successful: boolean) => {
      if (successful) {
        const title = this.translationService.get('workflow-item.' + this.type + '.notification.success.title');
        const content = this.translationService.get('workflow-item.' + this.type + '.notification.success.content');
        this.notificationsService.success(title, content);
      } else {
        const title = this.translationService.get('workflow-item.' + this.type + '.notification.error.title');
        const content = this.translationService.get('workflow-item.' + this.type + '.notification.error.content');
        this.notificationsService.error(title, content);
      }
      this.previousPage();
    });
  }

  /**
   * Navigates to the previous url
   * If there's not previous url, it continues to the mydspace page instead
   */
  previousPage() {
    this.routeService.getPreviousUrl().pipe(take(1))
      .subscribe((url) => {
        let params: Params = {};
        if (isEmpty(url)) {
          url = '/mydspace';
          params = this.previousQueryParameters;
        }
        if (url.split('?').length > 1) {
          for (const param of url.split('?')[1].split('&')) {
            params[param.split('=')[0]] = decodeURIComponent(param.split('=')[1]);
          }
        }
        void this.router.navigate([url.split('?')[0]], { queryParams: params });
      },
      );
  }

  /**
   * Performs the action of this workflow item action page
   * @param id The id of the WorkflowItem
   */
  abstract sendRequest(id: string): Observable<boolean>;

  /**
   * Returns the type of page
   */
  abstract getType(): string;
}