import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Store } from '@ngxs/store';
import {
  AddBreadcrumb,
  UpdateCurrentBreadcrumbName,
  PopLastBreadcrumbs,
  DeleteBreadcrumbsForProcess,
  DeleteLastPreviousPath,
  ClearBreadcrumbs,
} from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
import { ChangeCurrentRoute, AddProcess } from 'apps/sales/src/app/core/store/actions/process.actions';
import { Breadcrumb } from 'apps/sales/src/app/core/models/breadcrumb.model';
import { OrderItemListItemDTO } from '@swagger/oms';
import { ProcessSelectors } from 'apps/sales/src/app/core/store/selectors/process.selectors';
import { Process } from 'apps/sales/src/app/core/models/process.model';

@Injectable({ providedIn: 'root' })
export class ShelfNavigationService {
  constructor(private store: Store, private router: Router) {}

  async navigateToSearch() {
    const path = '/shelf/search';
    this.resetBreadcrumbs();
    this.navigateToRoute(path, 'Warenausgabe');
  }

  async navigateToDetails(
    order: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    },
    options: { replaceLastVisited: boolean } = { replaceLastVisited: false }
  ) {
    if (!order) {
      return this.navigateToSearch();
    }

    this.createTab();
    const path = this.getDetailsPath(order);
    const breadcrumb = this.getDetailsBreadcrumb(order);

    await this.navigateToRoute(path, breadcrumb);

    if (options.replaceLastVisited) {
      this.removePreviousPath();
    }
  }

  navigateToEdit(order: { orderNumber?: string; compartmentCode?: string; processingStatus?: number }) {
    if (!order) {
      return this.navigateToSearch();
    }
    this.createTab();
    const path = this.getDetailsPath({ ...order, edit: true });
    const breadcrumb = this.getEditBreadCrumb();

    this.navigateToRoute(path, breadcrumb);
  }

  updateDetailsNavigation(order: { orderNumber?: string; compartmentCode?: string; processingStatus?: number }) {
    if (!order) {
      return this.navigateToSearch();
    }
    const path = this.getDetailsPath(order);
    const breadcrumb = this.getDetailsBreadcrumb(order);
    this.replaceRoute(path, breadcrumb);
  }

  navigateToDetailsFromOrderToCompartment(data: { compartmentCode: string }) {
    if (!data) {
      return this.navigateToSearch();
    }
    const path = this.getDetailsPath(data);
    const breadcrumb = this.getDetailsBreadcrumb(data);
    this.replaceRoute(path, breadcrumb);
  }

  navigateToResultList({ searchQuery, numberOfHits }: { searchQuery: string; numberOfHits: number }) {
    this.createTab();
    const path = '/shelf/results';
    const breadcrumb = this.getResultListBreadcrumb(searchQuery, numberOfHits);
    this.navigateToRoute(path, breadcrumb);
  }

  navigateToHistory(orderitem: OrderItemListItemDTO) {
    this.navigateToRoute(this.getHistoryPath(orderitem), `Historie ${orderitem.orderItemSubsetId}`);
  }

  getHistoryPath(data: {
    orderId?: number;
    compartmentCode?: string;
    orderItemId?: number;
    orderItemSubsetId?: number;
    orderNumber?: string;
  }) {
    if (data.compartmentCode) {
      return `/shelf/details/compartment/${data.compartmentCode}/item/${data.orderItemId}/subset/${data.orderItemSubsetId}/history`;
    } else if (data.orderId) {
      return `/shelf/details/order/${data.orderNumber}/item/${data.orderItemId}/subset/${data.orderItemSubsetId}/history`;
    }
  }

  updateResultPageBreadcrumb(data: { numberOfHits: number; searchQuery: string }) {
    this.store.dispatch(new DeleteBreadcrumbsForProcess(1));
    this.store.dispatch(new AddBreadcrumb({ name: 'Warenausgabe', path: '/shelf/search' }, 'shelf'));
    const path = '/shelf/results';
    this.store.dispatch(
      new AddBreadcrumb(
        {
          name: `${data.searchQuery} (${data.numberOfHits} ${data.numberOfHits > 1 ? 'Ergebnisse' : 'Ergebnis'})`,
          path,
        },
        'shelf'
      )
    );
  }

  private replaceRoute(route: string, breadcrumbName: string) {
    this.router.navigate([route]);
    this.store.dispatch(new UpdateCurrentBreadcrumbName(breadcrumbName, 'shelf'));
  }

  private resetBreadcrumbs(): void {
    this.store.dispatch(new ClearBreadcrumbs('shelf'));
    this.store.dispatch(new AddBreadcrumb({ name: 'Warenausgabe', path: '/shelf' }, 'shelf', true));
  }

  private async navigateToRoute(route: string, breadcrumbName: string): Promise<boolean> {
    this.store.dispatch(
      new AddBreadcrumb(
        <Breadcrumb>{
          name: breadcrumbName,
          path: route,
        },
        'shelf'
      )
    );
    this.store.dispatch(new ChangeCurrentRoute(route));
    return this.router.navigate([route]);
  }

  public async navigateBackToDetails(
    data: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    },
    previous?: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    }
  ) {
    const replaceLastVisited = this.urlParamsHaveChanged(data, previous);
    console.log({ replaceLastVisited, data, previous });
    this.store.dispatch(new PopLastBreadcrumbs(this.getEditBreadCrumb()));

    if (previous) {
      this.store.dispatch(new PopLastBreadcrumbs(this.getDetailsBreadcrumb(previous)));
    }

    await this.navigateToDetails(data, { replaceLastVisited });
    if (replaceLastVisited) {
      this.removePreviousPath();
    }
  }

  public updateDetails(
    data: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    },
    previous?: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    }
  ) {
    if (previous) {
      this.store.dispatch(new PopLastBreadcrumbs(this.getDetailsBreadcrumb(previous)));
    }
    this.navigateToDetails(data, { replaceLastVisited: true });
  }

  private removePreviousPath() {
    this.store.dispatch(new DeleteLastPreviousPath());
  }

  private getResultListBreadcrumb(searchQuery: string, numberOfHits: number): string {
    return `${searchQuery} (${numberOfHits} Ergebnisse)`;
  }

  getDetailsBreadcrumb(data: { orderNumber?: string; compartmentCode?: string }): string {
    if (data.compartmentCode) {
      return `${data.compartmentCode}`;
    }
    return `${data.orderNumber}`;
  }

  getEditBreadCrumb(): string {
    return 'Bearbeiten';
  }

  private getDetailsPath(data: { orderNumber?: string; compartmentCode?: string; processingStatus?: number; edit?: boolean }): string {
    let url = '';
    if (data.compartmentCode) {
      url = `/shelf/details/compartment/${data.compartmentCode}/${data.processingStatus}`;
    } else {
      url = `/shelf/details/order/${data.orderNumber}/${data.processingStatus}`;
    }

    if (data.edit) {
      url += '/edit';
    }

    return url;
  }

  private createTab() {
    const processExists = this.store.selectSnapshot(ProcessSelectors.getProcessesCount) > 0;
    if (!processExists) {
      this.createProcess();
    }
  }

  private createProcess() {
    const newProcess = <Process>{
      id: 1,
      name: 'Vorgang 1',
      currentRoute: '/shelf/search',
    };

    this.store.dispatch(new AddProcess(newProcess));
    this.store.dispatch(
      new AddBreadcrumb(
        <Breadcrumb>{
          name: 'Abholfach',
          path: '/shelf/search',
        },
        'shelf'
      )
    );
  }

  private urlParamsHaveChanged(
    current: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    },
    previous?: {
      orderNumber?: string;
      compartmentCode?: string;
      processingStatus?: number;
    }
  ): boolean {
    if (!previous) {
      return false;
    }

    if (current.orderNumber && previous.orderNumber && current.orderNumber !== previous.orderNumber) {
      return true;
    }

    if (current.compartmentCode && previous.compartmentCode && current.compartmentCode !== previous.compartmentCode) {
      return true;
    }

    if (current.processingStatus && previous.processingStatus && current.processingStatus !== previous.processingStatus) {
      return true;
    }

    return false;
  }
}
