import {
  Component,
  ChangeDetectionStrategy,
  computed,
  ChangeDetectorRef,
  inject,
  DOCUMENT,
  signal,
} from '@angular/core';
import { AuthModule, AuthService } from '@core/auth';
import { StockService } from '@generated/swagger/wws-api';
import { first, map, retry, switchMap, take } from 'rxjs/operators';
import { ShellService } from '../shell.service';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { EnvironmentService } from '@core/environment';

import { CommonModule } from '@angular/common';
import { Config } from '@core/config';
import { BreadcrumbService } from '@core/breadcrumb';
import { IconComponent } from '@shared/components/icon';
import { RegexRouterLinkActiveDirective } from '@shared/directives/router-link-active';
import { WrongDestinationModalService } from '@modal/wrong-destination';
import {
  CustomerCreateNavigation,
  CustomerOrdersNavigationService,
  CustomerSearchNavigation,
  PickupShelfInNavigationService,
  PickUpShelfOutNavigationService,
  ProductCatalogNavigationService,
} from '@shared/services/navigation';
import { toObservable, toSignal } from '@angular/core/rxjs-interop';

import { TabService } from '@isa/core/tabs';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import { isaNavigationRemission2, isaNavigationReturn } from '@isa/icons';
import z from 'zod';
import { SelectedRewardShoppingCartResource } from '@isa/checkout/data-access';

@Component({
  selector: 'shell-side-menu',
  templateUrl: 'side-menu.component.html',
  styleUrls: ['side-menu.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    CommonModule,
    NgIconComponent,
    IconComponent,
    RouterModule,
    AuthModule,
    RegexRouterLinkActiveDirective,
  ],
  providers: [provideIcons({ isaNavigationReturn, isaNavigationRemission2 })],
})
export class ShellSideMenuComponent {
  #shellService = inject(ShellService);
  #authService = inject(AuthService);
  #stockService = inject(StockService);
  #app = inject(ApplicationService);
  #router = inject(Router);
  #route = inject(ActivatedRoute);
  #wrongDestinationModalService = inject(WrongDestinationModalService);
  #environment = inject(EnvironmentService);
  #catalogNavigationService = inject(ProductCatalogNavigationService);
  #customerOrdersNavigationService = inject(CustomerOrdersNavigationService);
  #config = inject(Config);
  #breadcrumbService = inject(BreadcrumbService);
  #customerSearchNavigation = inject(CustomerSearchNavigation);
  #customerCreateNavigation = inject(CustomerCreateNavigation);
  #pickUpShelfOutNavigation = inject(PickUpShelfOutNavigationService);
  #pickUpShelfInNavigation = inject(PickupShelfInNavigationService);
  #cdr = inject(ChangeDetectorRef);
  #document = inject(DOCUMENT);
  tabService = inject(TabService);
  #shoppingCartResource = inject(SelectedRewardShoppingCartResource);

  staticTabIds = Object.values(
    this.#config.get('process.ids', z.record(z.coerce.number())),
  );

  tabId = computed(() => {
    const tabId = this.tabService.activatedTab()?.id;
    if (this.staticTabIds.includes(tabId)) {
      return this.nextId();
    }
    return tabId || this.nextId();
  });

  tabId$ = toObservable(this.tabId);

  branchKey$ = this.#stockService.StockCurrentBranch().pipe(
    retry(3),
    map((x) => x.result.key),
  );

  section$ = this.#app.getSection$();

  processes$ = this.section$.pipe(
    switchMap((section) => this.#app.getProcesses$(section)),
  );

  processesCount$ = this.processes$.pipe(
    map((processes) => processes?.length ?? 0),
  );

  activeProcess$ = this.#app.activatedProcessId$.pipe(
    switchMap((processId) => this.#app.getProcessById$(processId)),
  );

  get isTablet() {
    return this.#environment.matchTablet();
  }

  nextId() {
    return Date.now();
  }

  customerBasePath$ = this.activeProcess$.pipe(
    map((process) => {
      if (
        !!process &&
        process.section === 'customer' &&
        process.type !== 'cart-checkout'
      ) {
        // Übernehme aktiven Prozess
        return `/kunde/${process.id}`;
      } else {
        // Über Guards wird ein neuer Prozess erstellt
        return '/kunde';
      }
    }),
  );

  customerSearchRoute = toSignal(
    this.getLastActivatedCustomerProcessId$().pipe(
      map((processId) => {
        return this.#customerSearchNavigation.defaultRoute({ processId });
      }),
    ),
  );

  customerCreateRoute = toSignal(
    this.getLastActivatedCustomerProcessId$().pipe(
      map((processId) => {
        return this.#customerCreateNavigation.defaultRoute({ processId });
      }),
    ),
  );

  customerRewardRoute = computed(() => {
    const routeName = 'reward';
    const tabId = this.tabService.activatedTab()?.id;
    return this.#router.createUrlTree(['/', tabId || this.nextId(), routeName]);
  });

  hasShoppingCartItems = computed(() => {
    return this.#shoppingCartResource.resource.value()?.items?.length > 0;
  });

  pickUpShelfOutRoutePath$ = this.getLastActivatedCustomerProcessId$().pipe(
    map((processId) => {
      if (processId) {
        // Übernehme aktiven Prozess
        return this.#pickUpShelfOutNavigation.defaultRoute({ processId }).path;
      } else {
        // Über Guards wird ein neuer Prozess erstellt
        return this.#pickUpShelfOutNavigation.defaultRoute({}).path;
      }
    }),
  );

  productRoutePath$ = this.getLastActivatedCustomerProcessId$().pipe(
    map((processId) => {
      if (processId) {
        // Übernehme aktiven Prozess
        return this.#catalogNavigationService.getArticleSearchBasePath(
          processId,
        ).path;
      } else {
        // Über Guards wird ein neuer Prozess erstellt
        return this.#catalogNavigationService.getArticleSearchBasePath().path;
      }
    }),
  );

  customerOrdersRoutePath$ = this.getLastActivatedCustomerProcessId$().pipe(
    map((processId) => {
      if (processId) {
        // Übernehme aktiven Prozess
        return this.#customerOrdersNavigationService.getCustomerOrdersBasePath(
          processId,
        ).path;
      } else {
        // Über Guards wird ein neuer Prozess erstellt
        return this.#customerOrdersNavigationService.getCustomerOrdersBasePath()
          .path;
      }
    }),
  );

  taskCalenderNavigation$ = this.getLastNavigationByProcessId(
    this.#config.get('process.ids.taskCalendar'),
    {
      path: ['/filiale', 'task-calendar'],
      queryParams: {},
    },
    '/filiale/task-calendar',
  );

  assortmentNavigation$ = this.getLastNavigationByProcessId(
    this.#config.get('process.ids.assortment'),
    {
      path: ['/filiale', 'assortment'],
      queryParams: {},
    },
  );

  pickUpShelfInRoutePath$ = this.getLastNavigationByProcessId(
    this.#config.get('process.ids.pickupShelf'),
    this.#pickUpShelfInNavigation.defaultRoute(),
    '/filiale/pickup-shelf',
  );

  // #4478 - RD // Abholfach - Routing löst Suche aus
  // pickUpShelfInListRoutePath$ = this.getLastNavigationByProcessId(
  //   this._config.get('process.ids.pickupShelf'),
  //   this._pickUpShelfInNavigation.listRoute()
  // );

  packageInspectionNavigation$ = this.getLastNavigationByProcessId(
    this.#config.get('process.ids.packageInspection'),
    {
      path: ['/filiale', 'package-inspection'],
      queryParams: {},
    },
  );

  get currentShelfView$() {
    return this.#route.queryParams.pipe(map((params) => params.view));
  }

  shelfExpanded = false;
  customerExpanded = signal(false);
  remissionExpanded = signal(false);

  customerActive(isActive: boolean) {
    if (isActive) {
      this.customerExpanded.set(true);
    }
  }

  toggleCustomerExpanded() {
    this.customerExpanded.set(!this.customerExpanded());
  }

  shelfActive(isActive: boolean) {
    if (isActive) {
      this.expandShelf();
    }
  }

  expandShelf() {
    this.shelfExpanded = true;
    this.#cdr.markForCheck();
  }

  getLastNavigationByProcessId(
    id: number,
    fallback?: { path: string[]; queryParams: unknown },
    pathContainsString?: string,
  ) {
    return this.#breadcrumbService.getBreadcrumbByKey$(id)?.pipe(
      map((breadcrumbs) => {
        const lastCrumb = breadcrumbs
          .filter((breadcrumb) => {
            /**
             * #4532 - Der optionale Filter wurde hinzugefügt Breadcrumbs mit fehlerhaften Pfad auszuschließen.
             * Dieser Filter kann entfernt werden, sobald die Breadcrumbs korrekt gesetzt werden. Jedoch konnte man bisher nicht feststellen,
             * woher die fehlerhaften Breadcrumbs kommen.
             */
            if (!pathContainsString) {
              // Wenn kein Filter gesetzt ist, dann wird der letzte Breadcrumb zurückgegeben
              return true;
            }

            const pathStr = Array.isArray(breadcrumb.path)
              ? breadcrumb.path.join('/')
              : breadcrumb.path;
            return pathStr.includes(pathContainsString);
          })
          // eslint-disable-next-line no-prototype-builtins
          .filter((breadcrumb) => !breadcrumb?.params?.hasOwnProperty('view'))
          .filter((breadcrumb) => !breadcrumb?.tags?.includes('reservation'))
          .filter((breadcrumb) => !breadcrumb?.tags?.includes('cleanup'))
          .filter(
            (breadcrumb) => !breadcrumb?.tags?.includes('wareneingangsliste'),
          )
          .filter((breadcrumb) => !breadcrumb?.tags?.includes('preview'))
          .reduce((last, current) => {
            if (!last) return current;

            if (last.changed > current.changed) {
              return last;
            } else {
              return current;
            }
          }, undefined);

        if (!lastCrumb) {
          return fallback;
        }

        // #4692 Return Fallback if Values contain undefined or null values, regardless if path is from type string or array
        if (typeof lastCrumb?.path === 'string') {
          if (
            lastCrumb?.path?.includes('undefined') ||
            lastCrumb?.path?.includes('null')
          ) {
            return fallback;
          }
        } else {
          const valuesToCheck = [];

          // eslint-disable-next-line no-unsafe-optional-chaining
          for (const value of lastCrumb?.path) {
            if (
              value?.outlets &&
              value?.outlets?.primary &&
              value?.outlets?.side
            ) {
              valuesToCheck.push(
                ...Object.values(value?.outlets?.primary),
                ...Object.values(value?.outlets?.side),
              );
            } else {
              valuesToCheck.push(value);
            }
          }

          if (this.checkIfArrayContainsUndefinedOrNull(valuesToCheck)) {
            return fallback;
          }
        }

        return { path: lastCrumb.path, queryParams: lastCrumb.params };
      }),
    );
  }

  checkIfArrayContainsUndefinedOrNull(array: unknown[]) {
    return (
      array?.includes(undefined) ||
      array?.includes('undefined') ||
      array?.includes(null) ||
      array?.includes('null')
    );
  }

  getLastActivatedCustomerProcessId$() {
    return this.tabId$;
  }

  closeSideMenu() {
    this.#shellService.closeSideMenu();
  }

  logout() {
    this.#authService.logout();
  }

  async resetBranch() {
    const process = await this.activeProcess$.pipe(first()).toPromise();
    if (process?.id) {
      this.#app.patchProcessData(process.id, { selectedBranch: undefined });
    }
  }

  focusSearchBox() {
    setTimeout(() => this.#document.getElementById('searchbox')?.focus(), 0);
  }

  async createProcess() {
    const process = await this.createCartProcess();
    this.navigateToCatalog(process);
  }

  async createCartProcess() {
    const nextProcessName = await this.getNextProcessName();

    const process: ApplicationProcess = {
      id: this.getNextProcessId(),
      type: 'cart',
      name: nextProcessName,
      section: 'customer',
      closeable: true,
    };

    this.#app.createProcess(process);

    return process;
  }

  async getNextProcessName() {
    let processes = await this.#app
      .getProcesses$('customer')
      .pipe(first())
      .toPromise();

    processes = processes.filter(
      (x) => x.type === 'cart' && x.name.startsWith('Vorgang '),
    );

    const maxProcessNumber = processes.reduce((max, process) => {
      const number = parseInt(process.name.replace('Vorgang ', ''), 10);
      return number > max ? number : max;
    }, 0);

    return `Vorgang ${maxProcessNumber + 1}`;
  }

  getNextProcessId() {
    return Date.now();
  }

  async navigateToCatalog(process: ApplicationProcess) {
    await this.#catalogNavigationService
      .getArticleSearchBasePath(process.id)
      .navigate();
  }

  navigateToDashboard() {
    this.#router.navigate(['/kunde', 'dashboard']);
  }

  async closeAllProcesses() {
    const processes = await this.processes$.pipe(take(1)).toPromise();

    processes.forEach((process) => this.#app.removeProcess(process.id));

    this.navigateToDashboard();
  }

  fetchAndOpenPackages = () =>
    this.#wrongDestinationModalService.fetchAndOpen();
}
