import {
  Component,
  OnInit,
  OnDestroy,
  ViewChild,
  ChangeDetectorRef,
  ElementRef,
  ChangeDetectionStrategy,
  ViewChildren,
  QueryList,
  ComponentRef,
} from '@angular/core';
import { Subject, Observable, BehaviorSubject } from 'rxjs';
import { takeUntil, filter, take, switchMap, catchError, delay, withLatestFrom, map, first, startWith, tap } from 'rxjs/operators';
import { RemissionResourceType, RemissionTargetType } from '../../models/remission-resource-type.model';
import { ResourceTypeSpecificModel } from '../../models/resource-type-specific-model.model';
import { CapacityTypeClientWrapper } from '../../models/capacity-type-client-wrapper.model';
import { RemissionSupplier, RemissionService, RemissionSourceType, RemissionProcess, ShippingDocument } from '@isa/remission';
import { Select, Store } from '@ngxs/store';
import { RemissionSelectors } from 'apps/sales/src/app/core/store/selectors/remission.selectors';
import { RemissionProcessStatuses } from 'apps/sales/src/app/core/models/remission-process-statuses.model';
import { RESOURCE_TYPE_SPECIFIC_MODEL_OPTIONS, RESOURCE_TYPE_SWITCH } from '../../constants/remission.constants';
import { isNullOrUndefined } from 'util';
import {
  SetRemissionProcess,
  SetRemissionCreated,
  SetRemissionFinishedProcessStatus,
  SetRemissionActiveView,
  ResetRemissionState,
} from 'apps/sales/src/app/core/store/actions/remission.actions';
import { RemissionHelperService } from '../../services/remission-helper.service';
import { RemissionListComponent } from '../../components/remission-list/remission-list.component';
import { AddBreadcrumb } from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
import { Router } from '@angular/router';
import { SetBranchProcessCurrentPath } from 'apps/sales/src/app/core/store/actions/branch-process.actions';
import { RemissionActiveView, RemissionFinishingProcessStatus } from '../../models';
import { fadeInWithDelay } from '../../animations/fadeIn.animation';

@Component({
  selector: 'app-remission-list-started',
  templateUrl: './remission-list-started.component.html',
  styleUrls: ['./remission-list-started.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  animations: [fadeInWithDelay(1.5)],
})
export class RemissionListStartedComponent implements OnInit, OnDestroy {
  @Select(RemissionSelectors.getRemissionProcessStatuses)
  remissionProcessStatuses$: Observable<RemissionProcessStatuses>;
  @Select(RemissionSelectors.getRemissionProcess)
  currentRemissionProcess$: Observable<RemissionProcess>;
  @Select(RemissionSelectors.getRemissionSource)
  currentRemissionSource$: Observable<RemissionResourceType>;
  @Select(RemissionSelectors.getRemissiontarget)
  currentRemissionTarget$: Observable<RemissionTargetType>;
  @Select(RemissionSelectors.getRemissionShippingDocumentstatus)
  shippingDocumentStatus$: Observable<boolean>;
  @Select(RemissionSelectors.getRemissionShippingDocument)
  shippingDocument$: Observable<ShippingDocument>;
  @Select(RemissionSelectors.getIsLoading)
  isLoading$: Observable<boolean>;
  @Select(RemissionSelectors.getActiveView)
  activeView$: Observable<RemissionActiveView>;

  remissionProcess$: Observable<RemissionProcess>;
  remissionSuppliers$ = this.remissionService.getRemissionTargets();
  remissionTargets$ = this.remissionService.getRemissionSources();
  showCreationPage$: Observable<boolean>;
  containerScroll$ = new BehaviorSubject<Event>(undefined);
  isCompleteButtomEnabled$: Observable<boolean>;

  @ViewChild('remissionList')
  remissionList: RemissionListComponent;
  @ViewChild('remissionListContainer')
  remissionListContainer: ElementRef;
  @ViewChild('shippingDocumentContainer')
  shippingDocumentContainer: ElementRef;

  @ViewChildren('capacitiesContainer')
  capacitiesRef: QueryList<ElementRef>;
  @ViewChildren('shippingDocumentContainer')
  shippingDocumentRef: QueryList<ElementRef>;

  destroy$ = new Subject();
  selectedRemissionResourceType: RemissionResourceType = RemissionResourceType.Central;
  selectedResourceTypeSpecificModel: ResourceTypeSpecificModel = RESOURCE_TYPE_SPECIFIC_MODEL_OPTIONS[this.selectedRemissionResourceType];
  capacities: CapacityTypeClientWrapper[] = [];

  resourceTypeSwitch = RESOURCE_TYPE_SWITCH;
  remissionProcessStatuses: RemissionProcessStatuses;
  processNeedsToBeRestoredFromCache = false;
  remissionListHits: number;
  hits: number;
  listLoaded = false;
  disabledCompleteRemissionButton = true;
  shippingDocumentCreationPage;
  shippingDocument: ShippingDocument;
  loaded = false;
  stopScrollStatus = false;
  loadShippingDocument = false;

  filtersExpanded = false;

  constructor(
    private remissionService: RemissionService,
    private store: Store,
    private remissionHelper: RemissionHelperService,
    private router: Router,
    private cdrf: ChangeDetectorRef
  ) {}

  ngOnInit() {
    this.initRemissionProcess();
    this.initViewController();
    this.initRemissionHelper();
    this.initAutomaticRedirect();
    this.initCompleteButtonStatus();
    this.initScrollRestoration();
  }

  initViewController() {
    this.showCreationPage$ = this.shippingDocumentStatus$.pipe(
      filter((isShippingDocumentCreated) => !isNullOrUndefined(isShippingDocumentCreated)),
      map((isShippingDocumentCreated) => !isShippingDocumentCreated)
    );
  }

  initScrollRestoration() {
    this.activeView$.pipe(takeUntil(this.destroy$)).subscribe((activeView) => {
      if (activeView === 'Warenbegleitschein') {
        this.resetShippingDocumentScrollPosition();
      } else {
        this.resetShippingDocumentScrollPosition(true);
      }
    });
  }

  initCompleteButtonStatus() {
    this.isCompleteButtomEnabled$ = this.shippingDocument$.pipe(
      map((shippingDocument) => !!shippingDocument && !!shippingDocument.products && !!shippingDocument.products.length),
      startWith(false)
    );
  }

  loadCurrentRemissionSource() {
    this.currentRemissionSource$
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        take(1)
      )
      .subscribe((source) => this.remissionHelper.updateFilters({ source }));
  }

  loadCurrentRemissionTarget() {
    this.currentRemissionTarget$
      .pipe(
        withLatestFrom(this.remissionSuppliers$),
        map(([target, suppliers]) => suppliers.find((supplier) => supplier.name === target)),
        filter((data) => !isNullOrUndefined(data)),
        take(1)
      )
      .subscribe((target) => this.remissionHelper.updateFilters({ target }));
  }

  initRemissionProcess() {
    this.remissionProcessStatuses$
      .pipe(
        takeUntil(this.destroy$),
        filter((status) => !isNullOrUndefined(status)),
        switchMap((status) => {
          let process$: Observable<RemissionProcess>;
          if (!status.created) {
            process$ = this.createProcess();
          } else {
            process$ = this.continueProcess();
          }

          return process$.pipe(
            tap((process) => console.log('initRemissionProcess', { process })),
            filter((process) => !isNullOrUndefined(process))
          );
        }),
        take(1),
        withLatestFrom(this.shippingDocument$)
      )
      .subscribe(([process, document]) => {
        console.log({ process, document });
        if (process.completed || (document && document.isCompleted)) {
          this.store.dispatch(new ResetRemissionState());
          this.navigateToFinishRemission();
        }
        this.store.dispatch(new SetRemissionProcess(process));
      });
  }

  initRemissionHelper() {
    this.remissionHelper.remissionListHits$
      .pipe(
        delay(0),
        filter((data) => !isNullOrUndefined(data)),
        takeUntil(this.destroy$)
      )
      .subscribe((hits) => {
        this.hits = hits;
        if (hits === 0) {
          this.listLoaded = false;
        } else {
          this.listLoaded = true;
        }
        if (hits >= 0) {
          this.remissionListHits = hits;
        }
      });

    this.remissionHelper.filtersUpdated$.pipe(takeUntil(this.destroy$)).subscribe(() => {
      setTimeout(() => {
        if (this.remissionList) {
          this.remissionList.setFullListLoadedToFalse();
        }
      }, 500);
    });
  }

  initAutomaticRedirect() {
    this.store
      .select(RemissionSelectors.getRemissionFinishingProcessStatus)
      .pipe(
        takeUntil(this.destroy$),
        filter((data) => !isNullOrUndefined(data)),
        first()
      )
      .subscribe((status) => {
        if (status === RemissionFinishingProcessStatus.finished) {
          this.navigateToFinishRemission();
        }
      });
  }

  continueProcess(): Observable<RemissionProcess> {
    return this.currentRemissionProcess$
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        take(1)
      )
      .pipe(
        switchMap((process) => {
          return this.remissionService.continueProcess(process);
        }),
        catchError(this.continueProcessErrorHandler)
      );
  }

  continueProcessErrorHandler = (error: any) => {
    console.error(error);
    this.processNeedsToBeRestoredFromCache = true;
    return this.createProcess();
  };

  createProcess(): Observable<RemissionProcess> {
    this.store.dispatch(new SetRemissionCreated(true));
    return this.remissionService.createProcess();
  }

  remissionSourcesFilter = (remissionSources: RemissionSourceType[]) => {
    return remissionSources && Array.isArray(remissionSources) && remissionSources.length === 2;
  };

  remissionSuppliersFilter = (remissionSuppliers: RemissionSupplier[]) => {
    return remissionSuppliers && Array.isArray(remissionSuppliers) && remissionSuppliers.length === 2;
  };

  restoreProcess = () => {
    this.processNeedsToBeRestoredFromCache = false;
    this.loadCurrentRemissionSource();
    this.loadCurrentRemissionTarget();
    this.remissionHelper.reApplyFilters(this.selectedRemissionResourceType);
  };

  completeShippingDocument() {
    this.store.dispatch(new SetRemissionFinishedProcessStatus(RemissionFinishingProcessStatus.start));
    this.navigateToFinishRemission();
  }

  filterToggled(state: boolean) {
    if (state) {
      setTimeout(() => {
        // HIMA-1045 smooth scroll the expanded options into view
        const container = document.getElementById('options');
        if (container) {
          container.scrollIntoView({ block: 'end', behavior: 'smooth' });
        }
      }, 300);
    }
  }

  navigateToFinishRemission() {
    const path = '/remission/finish';
    this.store.dispatch(
      new AddBreadcrumb(
        {
          path: path,
          name: 'Wannennummer',
        },
        'remission'
      )
    );
    this.router.navigate([path]);
    this.store.dispatch(new SetBranchProcessCurrentPath(path));
  }

  fullListLoaded() {
    const container = this.remissionListContainer.nativeElement;
    setTimeout(() => {
      container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
    }, 750);
    this.cdrf.detectChanges();
  }

  ngOnDestroy() {
    this.destroy$.next();
  }

  scrollHandler(event: Event) {
    this.containerScroll$.next(event);
  }

  navigateToWarenbegleitschein() {
    setTimeout(
      () =>
        this.shippingDocumentContainer.nativeElement.scrollIntoView({
          block: 'end',
          behavior: 'smooth',
        }),
      750
    );
  }

  navigateToProducts() {
    this.store.dispatch(new SetRemissionActiveView(RemissionActiveView.PRODUCTS));
  }

  private resetShippingDocumentScrollPosition(waitForAnimationToComplete: boolean = false) {
    if (!this.remissionListContainer) {
      return;
    }

    const initialScrollOffset = 300;
    let additionalScrollOffset = 0;

    if (!!this.capacitiesRef.first && this.capacitiesRef.first.nativeElement) {
      additionalScrollOffset = this.capacitiesRef.first.nativeElement.clientHeight;
    }

    const scrollOffset = initialScrollOffset + additionalScrollOffset;

    if (this.remissionListContainer.nativeElement.scrollTop < scrollOffset) {
      return;
    }

    if (waitForAnimationToComplete) {
      setTimeout(() => {
        this.remissionListContainer.nativeElement.scrollTop = scrollOffset;
      }, 450);
    } else {
      setTimeout(() => {
        this.remissionListContainer.nativeElement.scrollTop = scrollOffset;
      }, 450);
    }
  }
}
