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

@Injectable({ providedIn: 'root' })
export class CanActivateGoodsOutGuard {
  constructor(
    private readonly _applicationService: ApplicationService,
    private readonly _checkoutService: DomainCheckoutService,
    private readonly _router: Router,
  ) {}

  // !!! Ticket #3272 Code soll vorerst bestehen bleiben. Prozess Warenausgabe soll wieder Vorgang heißen (wie aktuell im Produktiv), bis zum neuen Navigationskonzept
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------

  // async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  //   const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();

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

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

  //   const lastActivatedCartCheckoutProcessId = (
  //     await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').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 (!!lastActivatedCartProcessId && lastActivatedCartProcessId === activatedProcessId) {
  //     await this.fromCartProcess(processes, route, lastActivatedCartProcessId);
  //     return false;
  //   } else if (!!lastActivatedCartCheckoutProcessId && lastActivatedCartCheckoutProcessId === activatedProcessId) {
  //     await this.fromCartCheckoutProcess(processes, route, lastActivatedCartCheckoutProcessId);
  //     return false;
  //   }

  //   if (!lastActivatedProcessId) {
  //     await this.fromGoodsOutProcess(processes, route);
  //     return false;
  //   } else {
  //     await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(lastActivatedProcessId)]));
  //   }

  //   return false;
  // }

  // // Bei offener Warenausgabe und Klick auf Footer Warenausgabe
  // async fromGoodsOutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
  //   const newProcessId = Date.now();
  //   await this._applicationService.createProcess({
  //     id: newProcessId,
  //     type: 'goods-out',
  //     section: 'customer',
  //     name: `Warenausgabe ${this.processNumber(processes.filter((process) => process.type === 'goods-out'))}`,
  //   });

  //   await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(newProcessId)]));
  // }

  // // Bei offener Artikelsuche/Kundensuche und Klick auf Footer Warenausgabe
  // async fromCartProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot, processId: number) {
  //   // Ändere type cart zu goods-out
  //   this._applicationService.patchProcess(processId, {
  //     id: processId,
  //     type: 'goods-out',
  //     section: 'customer',
  //     name: `Warenausgabe ${this.processNumber(processes.filter((process) => process.type === 'goods-out'))}`,
  //   });

  //   // Navigation
  //   await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
  // }

  // // Bei offener Bestellbestätigung, Artikelsuche/Kundensuche und Klick auf Footer Warenausgabe
  // 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 goods-out
  //   this._applicationService.patchProcess(processId, {
  //     id: processId,
  //     type: 'goods-out',
  //     section: 'customer',
  //     name: `Warenausgabe ${this.processNumber(processes.filter((process) => process.type === 'goods-out'))}`,
  //     data: {},
  //   });

  //   // Navigation
  //   await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
  // }

  // !!! Ticket #3272 Code soll vorerst bestehen bleiben. Prozess Warenausgabe soll wieder Vorgang heißen (wie aktuell im Produktiv), bis zum neuen Navigationskonzept
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------

  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 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;
    }

    if (!lastActivatedProcessId) {
      await this.fromGoodsOutProcess(processes, route);
      return false;
    } else {
      await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(lastActivatedProcessId)]));
    }

    return false;
  }

  // Bei offener Warenausgabe und Klick auf Footer Warenausgabe
  async fromGoodsOutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
    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._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(newProcessId)]));
  }

  // Bei offener Bestellbestätigung und Klick auf Footer Warenausgabe
  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 goods-out
    this._applicationService.patchProcess(processId, {
      id: processId,
      type: 'cart',
      section: 'customer',
      name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
      data: {},
    });

    // Navigation
    await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
  }

  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;
  }
}
