import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { CacheService } from '@core/cache';
import { Config } from '@core/config';
import { DomainRemissionService } from '@domain/remission';
import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators';

import { ReturnDTO } from '@generated/swagger/inventory-api';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { NEVER, Observable } from 'rxjs';
import { catchError, filter, first, map, shareReplay, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
import { ShortReceiptNumberPipe } from '../../pipes/short-receipt-number.pipe';
import { RemissionListComponentStore } from '../../remission-list/remission-list.component-store';
import { coerceBooleanProperty } from '@angular/cdk/coercion';

export interface ShippingDocumentDetailsState {
  remissionStarted?: boolean;
  return: ReturnDTO;
  packageNumber?: string;
}

@Component({
  selector: 'page-shipping-document-details',
  templateUrl: 'shipping-document-details.component.html',
  styleUrls: ['shipping-document-details.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [ShortReceiptNumberPipe],
  standalone: false,
})
export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDocumentDetailsState> implements OnInit {
  get processId() {
    return this._config.get('process.ids.remission');
  }

  notCompleted$: Observable<boolean>;

  returnId$: Observable<number>;

  hasItems$: Observable<boolean>;

  finishShippingDocumentDisabled$: Observable<boolean>;

  get remissionStarted() {
    return this.get((s) => s.remissionStarted);
  }

  get remissionStarted$() {
    return this.select((s) => s.remissionStarted);
  }

  get return() {
    return this.get((s) => s.return);
  }

  get firstReceipt() {
    return this.return.receipts?.find((_) => true)?.data;
  }

  get return$() {
    return this.select((s) => s.return);
  }

  get packageNumber$() {
    return this.select((s) => s.packageNumber);
  }

  get packageNumber() {
    return this.get((s) => s.packageNumber);
  }

  scrollPosition$ = this._breadcrumb.getBreadcrumbsByKeyAndTags$(this.processId, ['remission']).pipe(
    map((crumbs) => {
      const crumbParams = crumbs?.find((_) => true)?.params;

      if (crumbParams && Object.keys(crumbParams)?.find((key) => key === 'scroll_position')) {
        return { scroll_position: crumbParams['scroll_position'] ?? 0 };
      } else {
        return {};
      }
    }),
  );

  queryParams$ = this.scrollPosition$.pipe(
    withLatestFrom(this._activatedRoute.queryParams),
    map(([scrollPosition, queryParams]) => {
      return { ...queryParams, ...scrollPosition };
    }),
  );

  constructor(
    private _remissionListStore: RemissionListComponentStore,
    private _activatedRoute: ActivatedRoute,
    private _remissionService: DomainRemissionService,
    private _breadcrumb: BreadcrumbService,
    private _config: Config,
    private _shortReceiptNumberPipe: ShortReceiptNumberPipe,
    private _router: Router,
    private _cache: CacheService,
    private _modal: UiModalService,
  ) {
    super({ return: undefined });
  }

  ngOnInit() {
    this.removeBreadcrumbs();
    this.getReturn();

    this.finishShippingDocumentDisabled$ = this.return$.pipe(
      map((returnDto) => returnDto?.receipts?.find((_) => true)?.data?.items?.length === 0),
    );

    this.notCompleted$ = this.return$.pipe(map((returnDto) => !returnDto?.completed && !this.remissionStarted));

    this.returnId$ = this.return$.pipe(map((returnDto) => returnDto?.id));

    this.hasItems$ = this.return$.pipe(
      map((returnDto) => returnDto?.receipts?.find((_) => true)?.data?.items?.length > 0),
    );
  }

  removeBreadcrumbs() {
    this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'add-product']);
    this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'create']);
    this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'finish-shipping-document']);
    this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'finish-remission']);
  }

  async navigateBack() {
    const queryParams = await this.queryParams$.pipe(first()).toPromise();
    this.remissionStarted
      ? this._router.navigate(['../list'], { relativeTo: this._activatedRoute, queryParams })
      : this._router.navigate(['..'], { relativeTo: this._activatedRoute });
  }

  async addOrUpdateBreadcrumbIfNotExists(returnDto: ReturnDTO) {
    const packageNumber = await this.packageNumber$.pipe(first()).toPromise();
    const params = await this.queryParams$.pipe(first()).toPromise();
    if (packageNumber) {
      const shortPackageNumber = this._shortReceiptNumberPipe.transform(packageNumber);
      this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
        key: this.processId,
        name: `${this.remissionStarted ? `Warenbegleitschein #${shortPackageNumber}` : `#${shortPackageNumber}`}`,
        path: this.remissionStarted
          ? `/filiale/remission/${returnDto.id}/shipping-document`
          : `/filiale/remission/shipping-documents/${returnDto.id}`,
        section: 'branch',
        params,
        tags: ['remission', 'shipping-documents', 'details'],
      });
    }
  }

  deleted() {
    // Cache leeren und Reload bei Wechsel zurück zur Liste triggern
    this._remissionListStore.clearCache();
    this._remissionListStore._triggerReload$.next(true);

    this.navigateBack();
  }

  itemDeleted() {
    // Cache leeren und Reload bei Wechsel zurück zur Liste triggern
    this._remissionListStore.clearCache();
    this._remissionListStore._triggerReload$.next(true);

    this.reloadReturn();
  }

  async complete() {
    if (!this.get((s) => s.packageNumber)) {
      const returnId = this.return.id;
      const firstReceiptId = this.firstReceipt?.id;
      this._router.navigate(['/filiale/remission', returnId, 'finish-shipping-document', firstReceiptId], {
        queryParams: { complete: true },
      });
    } else {
      if (await this.completeReceipt()) {
        await this.completeReturn();
      }
    }
  }

  async completeReceipt() {
    const returnId = this.return?.id;
    const receiptId = this.firstReceipt?.id;
    const packageNumber = this.packageNumber;

    if (receiptId) {
      if (!packageNumber) {
        await this._router.navigate(['/filiale/remission', returnId, 'finish-shipping-document', receiptId], {
          queryParams: { complete: true },
        });
        return false;
      }

      try {
        await this._remissionService.completeReceipt(returnId, receiptId);
        return true;
      } catch (err) {
        this._modal.error('Fehler beim Abschließen des Warenbegleitscheins', err);
      }
    } else {
      this._modal.error('Fehler beim Abschließen des Warenbegleitscheins', new Error('Keine gültige ID'));
    }
    return false;
  }

  async completeReturn() {
    const returnId = this.return?.id;

    if (returnId) {
      try {
        await this._remissionService.completeReturn(returnId);

        await this._router.navigate(['/filiale', 'remission', returnId, 'finish-remission'], {
          relativeTo: this._activatedRoute,
          queryParams: { ...this.cleanupQueryParams(this._activatedRoute.snapshot.queryParams) },
        });
      } catch (err) {
        this._modal.open({
          content: UiErrorModalComponent,
          title: 'Fehler beim Abschließen der Remission',
          data: err,
        });
      }
    } else {
      this._modal.open({
        content: UiErrorModalComponent,
        title: 'Fehler beim Abschließen der Remission',
        data: new Error('Keine gültige ID'),
      });
    }
  }

  cleanupQueryParams(params: Record<string, string> = {}) {
    const clean = { ...params };
    delete clean['scroll_position'];

    for (const key in clean) {
      if (Object.prototype.hasOwnProperty.call(clean, key)) {
        if (clean[key] == undefined) {
          delete clean[key];
        }
      }
    }

    return clean;
  }

  reloadReturn = this.effect(($) =>
    $.pipe(
      tap((_) => {
        this._cache.delete({ processId: String(this.processId) });
        this.getReturn();
      }),
    ),
  );

  getReturn = this.effect(($) =>
    $.pipe(
      withLatestFrom(this._activatedRoute.params),
      tap(([_, params]) =>
        params?.id
          ? this.patchState({ remissionStarted: false })
          : params?.returnId
            ? this.patchState({ remissionStarted: true })
            : '',
      ),
      map(([_, params]) => params?.id ?? params?.returnId),
      filter((id) => !!id),
      switchMap((id) => this._remissionService.getReturn(id)),
      tapResponse(
        (r: ReturnDTO) => {
          const firstReceipt = r?.receipts?.find((_) => true)?.data;
          const packageNumber =
            firstReceipt?.packages?.find((_) => true)?.data?.packageNumber ??
            this._activatedRoute?.snapshot?.params?.packageNumber ??
            '';
          this.setPackageNumber(packageNumber);
          this.setReturn(r);

          this.addOrUpdateBreadcrumbIfNotExists(r);

          if (coerceBooleanProperty(this._activatedRoute.snapshot.queryParams?.complete)) {
            this.complete();
          }
        },
        (err) => {
          this.navigateBack();
          return NEVER;
        },
      ),
      catchError(() => {
        this.navigateBack();
        return NEVER;
      }),
    ),
  );

  setPackageNumber = this.updater<string>((state, packageNumber) => ({
    ...state,
    packageNumber,
  }));

  setReturn = this.updater<ReturnDTO>((state, r) => ({
    ...state,
    return: r,
  }));

  continue(addQueryParams?: boolean) {
    const packageNumber = this.get((s) => s.packageNumber);
    const returnId = this.get((s) => s.return.id);

    let queryParams = {};

    if (addQueryParams) {
      queryParams = this._activatedRoute.snapshot.queryParams;
    }

    if (!packageNumber) {
      const receiptId = this.firstReceipt?.id;
      this._router.navigate(['/filiale/remission', returnId, 'finish-shipping-document', receiptId], {
        queryParams,
      });
    } else {
      console.log('packageNumber', packageNumber);
      this._router.navigate(['/filiale/remission', returnId, packageNumber, 'list'], {
        queryParams,
      });
    }
  }
}
