import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { DomainCheckoutService } from '@domain/checkout';
import { ProductCatalogNavigationService } from '@shared/services/navigation';
import { first } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class CanActivateProductGuard {
  constructor(
    private readonly _applicationService: ApplicationService,
    private readonly _checkoutService: DomainCheckoutService,
    private readonly _navigationService: ProductCatalogNavigationService,
  ) {}

  async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
    let lastActivatedProcessId = (
      await this._applicationService
        .getLastActivatedProcessWithSectionAndType$('customer', 'cart')
        .pipe(first())
        .toPromise()
    )?.id;

    const lastActivatedCartCheckoutProcessId = (
      await this._applicationService
        .getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout')
        .pipe(first())
        .toPromise()
    )?.id;

    const lastActivatedGoodsOutProcessId = (
      await this._applicationService
        .getLastActivatedProcessWithSectionAndType$('customer', 'goods-out')
        .pipe(first())
        .toPromise()
    )?.id;

    const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();

    // Darf nur reinkommen wenn der aktuell aktive Tab ein Bestellabschluss Tab ist
    if (!!lastActivatedCartCheckoutProcessId && lastActivatedCartCheckoutProcessId === activatedProcessId) {
      await this.fromCartCheckoutProcess(processes, route, lastActivatedCartCheckoutProcessId);
      return false;
    } else if (!!lastActivatedGoodsOutProcessId && lastActivatedGoodsOutProcessId === activatedProcessId) {
      await this.fromGoodsOutProcess(processes, route, lastActivatedGoodsOutProcessId);
      return false;
    }

    if (!lastActivatedProcessId) {
      await this.fromCartProcess(processes);
      return false;
    } else {
      await this._navigationService.getArticleSearchBasePath(lastActivatedProcessId).navigate();
    }

    return false;
  }

  // Bei offener Artikelsuche/Kundensuche und Klick auf Footer Artikelsuche
  async fromCartProcess(processes: ApplicationProcess[]) {
    const newProcessId = Date.now();
    await this._applicationService.createProcess({
      id: newProcessId,
      type: 'cart',
      section: 'customer',
      name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
    });

    await this._navigationService.getArticleSearchBasePath(newProcessId).navigate();
  }

  // Bei offener Warenausgabe und Klick auf Footer Artikelsuche
  async fromGoodsOutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot, processId: number) {
    const buyer = await this._checkoutService.getBuyer({ processId }).pipe(first()).toPromise();
    const customerFeatures = await this._checkoutService.getCustomerFeatures({ processId }).pipe(first()).toPromise();
    const name = buyer
      ? customerFeatures?.b2b
        ? buyer.organisation?.name
          ? buyer.organisation?.name
          : buyer.lastName
        : buyer.lastName
      : `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`;

    // Ändere type goods-out zu cart
    this._applicationService.patchProcess(processId, {
      id: processId,
      type: 'cart',
      section: 'customer',
      name,
    });

    // Navigation
    await this._navigationService.getArticleSearchBasePath(processId).navigate();
  }

  // Bei offener Bestellbestätigung und Klick auf Footer Artikelsuche
  async fromCartCheckoutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot, processId: number) {
    // Um alle Checkout Daten zu resetten die mit dem Prozess assoziiert sind
    this._checkoutService.removeProcess({ processId });

    // Ändere type cart-checkout zu cart
    this._applicationService.patchProcess(processId, {
      id: processId,
      type: 'cart',
      section: 'customer',
      name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
      data: {},
    });

    // Navigation
    await this._navigationService.getArticleSearchBasePath(processId).navigate();
  }

  getUrlFromSnapshot(route: ActivatedRouteSnapshot, url: string[] = []): string[] {
    url.push(...route.url.map((segment) => segment.path));
    if (route.firstChild) {
      return this.getUrlFromSnapshot(route.firstChild, url);
    }
    return url.filter((segment) => !!segment);
  }

  processNumber(processes: ApplicationProcess[]) {
    const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
    return !!processNumbers && processNumbers.length > 0 ? this.findMissingNumber(processNumbers) : 1;
  }

  findMissingNumber(processNumbers: number[]) {
    for (let missingNumber = 1; missingNumber < Math.max(...processNumbers); missingNumber++) {
      if (!processNumbers.find((number) => number === missingNumber)) {
        return missingNumber;
      }
    }
    return Math.max(...processNumbers) + 1;
  }
}
