import { Component, OnInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
import { OrderDTO, OrderItemSubsetDTO } from '@swagger/oms';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { orderStatusMapper, OrderStatus, activeOrderStatusMapper } from 'apps/sales/src/app/core/mappings/shelf.mapping';
import { DatePipe } from '@angular/common';
import { CollectingShelfService } from 'apps/sales/src/app/core/services/collecting-shelf.service';
import { SetEditOrder } from 'apps/sales/src/app/core/store/actions/collecting-shelf.action';
import { Store } from '@ngxs/store';
import { Subject, of, Observable } from 'rxjs';
import { takeUntil, catchError, concatMap } from 'rxjs/operators';

export enum FieldType {
  item,
  subsetItem,
}

@Component({
  selector: 'app-order-overview-edit',
  templateUrl: './order-overview-edit.component.html',
  styleUrls: ['./order-overview-edit.component.scss'],
})
export class OrderOverviewEditComponent implements OnInit, OnDestroy {
  @Input() set _order(val: OrderDTO) {
    if (val) {
      this.order = val;
      this.initializeData();
    }
  }
  order: OrderDTO;
  @Output() statusChanged = new EventEmitter<string>();
  @Output() compartmentCodeChanged = new EventEmitter<string>();
  @Input() compartmentCode: string;
  orderForm: FormGroup;
  sumbited = false;
  postedPickUpDate: Date;
  pickUpDateOptions = ['um 2 Wochen verlängern', 'um 4 Wochen verlängern'];
  statusList: { key: string; value: string }[] = [];
  status: { key: string; value: string };
  postedStatus: string;
  isDeletedStatus = false;
  arrived = false;
  destroy$ = new Subject();

  get f() {
    return this.orderForm.controls;
  }

  get s() {
    return (this.orderForm.controls.processingStatus as FormGroup).controls;
  }

  constructor(private fb: FormBuilder, private datePipe: DatePipe, private shelfService: CollectingShelfService, private store: Store) {}

  ngOnInit() {
    this.initializeData();
  }

  ngOnDestroy() {}

  initializeData() {
    if (this.order) {
      this.buildForm(this.fb, { compartmentCode: this.compartmentCode, order: this.order });
    }
  }

  buildForm(fb: FormBuilder, model: { compartmentCode: string; order: OrderDTO }) {
    let orderDate = '';
    if (model.order.orderDate) {
      orderDate = this.datePipe.transform(new Date(model.order.orderDate), 'dd.MM.yy | HH:mm') + ' Uhr';
    }
    let pickUpDate = '';
    if (
      model.order.items &&
      model.order.items[0] &&
      model.order.items[0].data &&
      model.order.items[0].data.subsetItems &&
      model.order.items[0].data.subsetItems[0].data &&
      model.order.items[0].data.subsetItems[0].data.compartmentStop
    ) {
      pickUpDate = this.datePipe.transform(new Date(model.order.items[0].data.subsetItems[0].data.compartmentStop), 'dd.MM.yy');
      this.postedPickUpDate = new Date(model.order.items[0].data.subsetItems[0].data.compartmentStop);
    }
    this.statusList = Object.keys(activeOrderStatusMapper).map((key) => {
      return { key: key, value: activeOrderStatusMapper[key] };
    });
    let status: number;
    if (
      model.order.items &&
      model.order.items[0] &&
      model.order.items[0].data &&
      model.order.items[0].data.subsetItems &&
      model.order.items[0].data.subsetItems[0].data &&
      model.order.items[0].data.subsetItems[0].data.processingStatus
    ) {
      status = model.order.items[0].data.subsetItems[0].data.processingStatus;
      this.isDeletedStatus = status === OrderStatus.CanceledByBuyer || status === OrderStatus.CanceledByRetailer;
      this.arrived = status === OrderStatus.Arrived;
      this.status = { key: status + '', value: orderStatusMapper[status] };
    }
    this.postedStatus = orderStatusMapper[status];
    this.orderForm = fb.group({
      compartmentCode: [model.compartmentCode ? model.compartmentCode : '', Validators.required],
      processingStatus: fb.group({
        key: [status ? status : null],
        value: [status ? orderStatusMapper[status] : null],
      }),
      order_number: [model.order.orderNumber, Validators.required],
      order_date: [orderDate, Validators.required],
      compartmentStop: [pickUpDate, Validators.required],
    });
    this.orderForm.disable();
  }

  enableInput(field: string, input: any) {
    const control = this.orderForm.get(field);
    if (field === 'compartmentCode') {
      this.compartmentCodeChanged.emit(control.value);
    }
    if (control.disabled) {
      control.enable();
      input.focus();
      this.sumbited = false;
    } else if (control.valid && control.dirty) {
      this.submit(field);
      this.sumbited = true;
      control.disable();
    } else if (control.valid && !control.dirty) {
      this.sumbited = true;
      control.disable();
    } else if (!control.valid) {
      this.sumbited = true;
    }
  }

  enableDropdown(field: string) {
    const control = this.orderForm.get(field);
    if (control.disabled) {
      control.enable();
      this.sumbited = false;
    } else if (control.valid && control.dirty) {
      this.submit(field);
      this.sumbited = true;
      control.disable();
    } else if (control.valid && !control.dirty) {
      this.sumbited = true;
      control.disable();
    } else if (!control.valid) {
      this.sumbited = true;
    }
  }

  enableFormGroup(group: string, field: string) {
    const control = this.orderForm.get(group).get(field);
    if (control.disabled) {
      control.enable();
      this.sumbited = false;
    } else if (control.valid && control.dirty) {
      this.submit(group);
      this.sumbited = true;
      control.disable();
    } else if (control.valid && !control.dirty) {
      this.sumbited = true;
      control.disable();
    } else if (!control.valid) {
      this.sumbited = true;
    }
  }

  clear(field: string) {
    this.orderForm.get(field).patchValue(null);
  }

  clearPickUpdate() {
    const control = this.orderForm.get('compartmentStop');
    const dateFormated = this.datePipe.transform(new Date(this.postedPickUpDate), 'dd.MM.yy');
    control.patchValue(dateFormated);
    control.disable();
  }

  clearStatus() {
    const control = this.orderForm.get('processingStatus');
    control.patchValue(this.postedStatus);
    control.disable();
  }

  pickUpDateSelected(selection: string) {
    this.orderForm.get('compartmentStop').patchValue(selection);
    this.orderForm.get('compartmentStop').markAsDirty();
  }

  statusSelected(selection: { key: string; value: string }) {
    this.status = selection;
    this.statusChanged.emit(selection.key);
    this.orderForm.get('processingStatus').get('key').patchValue(selection.key);
    this.orderForm.get('processingStatus').get('value').patchValue(selection.value);
    this.orderForm.get('processingStatus').get('value').markAsDirty();
  }

  submit(field: string) {
    const control = this.orderForm.get(field);
    if (field === 'compartmentStop') {
      this.pickUpDateSubmited(control.value);
      return;
    }
    if (this.order.items && this.order.items.length > 0) {
      if (field === 'compartmentCode') {
        this.compartmentCode = control.value;
      }
      const patchingSubsetItemSequentially$: Observable<{
        orderId: number;
        orderItemId: number;
        orderItemSubsetId: number;
        orderItemSubsetDTO: OrderItemSubsetDTO;
      }> = new Observable((observer) => {
        this.order.items.forEach((item) => {
          if (item.data && item.data.subsetItems && [0] && item.data.subsetItems[0].data && item.data.subsetItems[0].data.id) {
            const orderItemSubsetId = item.data.subsetItems[0].data.id;
            const orderItemsubset = <OrderItemSubsetDTO>{};
            orderItemsubset[field] = field === 'processingStatus' ? control.get('key').value : control.value;
            observer.next({
              orderId: this.order.id,
              orderItemId: item.id,
              orderItemSubsetId: orderItemSubsetId,
              orderItemSubsetDTO: orderItemsubset,
            });
          }
        });
      });
      if (field === 'processingStatus') {
        this.listenForStatusChanges(patchingSubsetItemSequentially$);
      } else {
        this.listenForNeddedChangesToBeDone(patchingSubsetItemSequentially$);
      }
    }
  }

  listenForNeddedChangesToBeDone(
    patchingSubsetItemSequentially$: Observable<{
      orderId: number;
      orderItemId: number;
      orderItemSubsetId: number;
      orderItemSubsetDTO: OrderItemSubsetDTO;
    }>
  ) {
    patchingSubsetItemSequentially$
      .pipe(
        takeUntil(this.destroy$),
        concatMap((data) => {
          return this.shelfService.patchOrderItemSubsetRreturningItemId(
            data.orderId,
            data.orderItemId,
            data.orderItemSubsetId,
            data.orderItemSubsetDTO
          );
        }),
        catchError((error) => {
          console.error(error);
          return of(undefined);
        })
      )
      .subscribe((response: { itemId: number; result: OrderItemSubsetDTO }) => {
        if (response) {
          this.updateSubsetOfItem(response.result, response.itemId);
        }
      });
  }

  listenForStatusChanges(
    patchingSubsetItemSequentially$: Observable<{
      orderId: number;
      orderItemId: number;
      orderItemSubsetId: number;
      orderItemSubsetDTO: OrderItemSubsetDTO;
    }>
  ) {
    patchingSubsetItemSequentially$
      .pipe(
        takeUntil(this.destroy$),
        concatMap((data) => {
          return this.shelfService.editOrderArticleStatus(
            data.orderId,
            data.orderItemId,
            data.orderItemSubsetId,
            data.orderItemSubsetDTO.quantity,
            data.orderItemSubsetDTO.processingStatus
          );
        }),
        catchError((error) => {
          console.error(error);
          return of(undefined);
        })
      )
      .subscribe((response: { itemId: number; result: OrderItemSubsetDTO }) => {
        if (response) {
          this.updateSubsetOfItem(response.result, response.itemId);
        }
      });
  }

  updateSubsetOfItem(orderItemSubset: OrderItemSubsetDTO, itemId: number) {
    this.order = {
      ...this.order,
      items: this.order.items.map((item) => {
        if (item.id === itemId) {
          return { ...item, data: { ...item.data, subsetItems: [{ ...item.data.subsetItems[0], data: orderItemSubset }] } };
        }
        return item;
      }),
    };
    this.store.dispatch(new SetEditOrder(this.order));
    this.initializeData();
  }

  pickUpDateSubmited(selection: string) {
    switch (selection) {
      case 'um 2 Wochen verlängern':
        this.extendPickUpPeriod(2);
        break;
      case 'um 4 Wochen verlängern':
        this.extendPickUpPeriod(4);
        break;
      default:
        break;
    }
  }

  extendPickUpPeriod(weeks: 2 | 4) {
    if (this.order) {
      const existingDate = new Date(this.postedPickUpDate);
      const daysToAdd = weeks * 7;
      const extendedDate = new Date(
        existingDate.getFullYear(),
        existingDate.getMonth(),
        existingDate.getDate() + daysToAdd,
        existingDate.getHours(),
        existingDate.getMinutes(),
        existingDate.getSeconds(),
        existingDate.getMilliseconds()
      );
      const orderId = this.order.id;
      const items = this.order.items;
      items.forEach((orderItem) => {
        const orderItemId = orderItem.id;
        if (orderItem && orderItem.data && orderItem.data.subsetItems && orderItem.data.subsetItems[0]) {
          const orderItemSubsetId = orderItem.data.subsetItems[0].id;
          this.shelfService
            .extendPickUpPeriod(orderId, orderItemId, orderItemSubsetId, extendedDate)
            .toPromise()
            .then((response) => {
              if (response) {
                this.updateSubsetOfItem(response, orderItem.id);
              }
            })
            .catch((error) => {
              console.error(error);
            });
        }
      });
    }
  }
}
