import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { DialogContentBase, DialogRef } from '@progress/kendo-angular-dialog';
import { Observable, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthService } from 'src/app/auth/services/auth.service';
import { SaleProduct, Stock } from 'src/app/models/sale-product.model';
import { ProductService } from 'src/app/services/product.service';
import { ShoppingService } from 'src/app/services/shopping.service';
import { AddItemAction } from '../../store/actions/shopping.action';
import { SaleState } from '../../store/models/sale-state.model';
import { ShoppingItem } from '../../store/models/shopping-item';
import { environment } from '../../../../environments/environment.prod';
import { Customer } from 'src/app/models/customer.model';
import { LotProduct } from 'src/app/models/lot-product.model';
import { State, process } from '@progress/kendo-data-query';
import { AddEvent, CancelEvent, CellClickEvent, CellCloseEvent, GridComponent, GridDataResult, RemoveEvent, SaveEvent } from '@progress/kendo-angular-grid';
import { Keys } from '@progress/kendo-angular-common';
import { EditService } from 'src/app/services/product-lot.service';

@Component({
  selector: 'app-product-modal',
  templateUrl: './product-modal.component.html',
  styleUrls: ['./product-modal.component.scss',
    '../product-card/product-card.component.scss']
})
export class ProductModalComponent extends DialogContentBase implements OnInit, OnDestroy, AfterViewInit {
  @Input() product: SaleProduct;
  @Input() shoppingItem: ShoppingItem;

  @Output() public submitForm: EventEmitter<SaleProduct> = new EventEmitter();
  shoppingItens: ShoppingItem[] = [];
  shoppingItens$: Observable<ShoppingItem[]>;
  subscriptionStock: Subscription;
  subscriptionItensShopping: Subscription;
  subscriptionLotProduct: Subscription;
  updatePrice = false;
  form: FormGroup;
  quantityOk = true;
  stockValid = true;
  listPrice: number;
  salePrice: number;
  loading$: Observable<boolean>;
  error$: Observable<Error>;
  stock$: Observable<Stock[]>;
  error: Error = null;
  showDescription = false;
  textShowMore = 'Ver mais';
  public data: any = {
    deliveryType: null,
    store: null,
    stockStore: null,
    quantity: 1
  };

  public createFormGroup = (dataItem) =>
    new FormGroup({
      Discontinued: new FormControl(dataItem.Discontinued),
      ProductID: new FormControl(dataItem.ProductID),
      ProductName: new FormControl(dataItem.ProductName, Validators.required),
      UnitPrice: new FormControl(dataItem.UnitPrice),
      UnitsInStock: new FormControl(
        dataItem.UnitsInStock,
        Validators.compose([
          Validators.required,
          Validators.pattern("^[0-9]{1,3}"),
        ])
      ),
    });

  public matches = (el, selector) =>
    (el.matches || el.msMatchesSelector).call(el, selector);

  public dataDelivery = [{ type: 'RI', description: 'Retira imediata' },
  { type: 'EN', description: 'Entrega' },
  { type: 'RP', description: 'Retira posterior' },
 /* { type: 'RA', description: 'Retira posterior (Imediata)' },*/
  { type: 'EF', description: 'Entrega futura' },
  ];

  /* Variaveis para mensagem */
  showInformation = false;
  titleInformation = 'Pedido de venda';
  messageInformation = '';
  informationDescription = '';

  public imageWidth = '150px';
  public imageHeight = '180px';


  /* edit Price */
  editPrice = false;
  @ViewChildren('inputPrice') inputPrice: QueryList<ElementRef>;
  @ViewChild(GridComponent)
  private grid: GridComponent;

  returnShowInformation() {
    this.showInformation = false;
  }
  /* FIM - Variaveis para mensagem */

  /* Controle para lotes do produto */
  showLotProduct = false;
  customerId = 0;
  lotProduct$: Observable<LotProduct[]>;
  lotProduct: LotProduct[];
//  public view: Observable<GridDataResult>;

  returnShowLotProduct() {
    this.showLotProduct = false;
  }
  public gridState: State = {
    sort: [],
    skip: 0,
    take: 5,
  };

  public changes = {};

  public view: any[];

  public formGroup: FormGroup;

  private editedRowIndex: number;
  private docClickSubscription: Subscription = new Subscription();
  private isNew: boolean;


  /* FIM - Controle para lotes do produto */

  constructor(
    public dialog: DialogRef,
    private fb: FormBuilder,
    public shoppingService: ShoppingService,
    private productService: ProductService,
    private store: Store<SaleState>,
    private readonly authService: AuthService,
    private formBuilder: FormBuilder,
    public editService: EditService,
    private renderer: Renderer2
  ) {
    super(dialog);
  }

  ngOnDestroy(): void {
    if (this.subscriptionStock) {
      this.subscriptionStock.unsubscribe();
    }
    if (this.subscriptionItensShopping) {
      this.subscriptionItensShopping.unsubscribe();
    }
    if (this.subscriptionLotProduct) {
      this.subscriptionLotProduct.unsubscribe();
    }
    this.docClickSubscription.unsubscribe();
  }

  ngOnInit(): void {

    this.docClickSubscription.add(
      this.renderer.listen("document", "click", this.onDocumentClick.bind(this))
    );

    this.shoppingItens$ = this.store.select(store => store.shopping.list);
    this.subscriptionItensShopping = this.shoppingItens$.subscribe(itens => this.shoppingItens = itens);


    this.form = this.fb.group({
      quantity: new FormControl(this.shoppingItem != null ? this.shoppingItem.quantity : this.product.mutiple.toFixed(2), []),
      salePrice: new FormControl(this.shoppingItem != null ? this.shoppingItem.price : this.product.salePrice, []),
      store: new FormControl(this.shoppingItem != null ? this.shoppingItem.stockStore : this.authService.getStore(), []),
      deliveryType: new FormControl(this.shoppingItem != null ? this.shoppingItem.deliveryType : '', []),
      price: new FormControl(this.shoppingItem != null ? this.shoppingItem.price : this.product.salePrice, []),
      description: new FormControl(this.shoppingItem != null ? this.shoppingItem.auxDescription : '', []),
      addUpQuantity: new FormControl(this.shoppingItem != null ? this.shoppingItem.percentUpQuantity > 0 : false, []),
      originalQuantity: new FormControl(this.shoppingItem != null ? this.shoppingItem.upQuantity : 0, []),
      environment: new FormControl(this.shoppingItem != null ? this.shoppingItem.environment : '', []),
    });
    this.listPrice = (this.shoppingItem != null ? this.shoppingItem.listPrice : this.product.listPrice);
    this.salePrice = (this.shoppingItem != null ? this.shoppingItem.price : this.product.salePrice);
    this.form.valueChanges.subscribe((_) => {
      const oldValue = this.form.get('quantity').value;
      this.quantityOk = Number.parseFloat(oldValue) <= this.product.stock;
    });
    this.loading$ = this.store.select(store => store.shopping.loading);
    this.error$ = this.store.select(store => store.shopping.error);
    this.error$.subscribe((error) => {
      this.error = error;
    });
    this.stock$ = this.productService.getStocks(this.authService.getStore(), this.product.idProduct);
    const customer: Customer = JSON.parse(localStorage.getItem('customer'));
    this.customerId = (customer !== null) ? customer.customerId : 1;

    //  this.lotProduct$ = this.shoppingService.getLotProduct(this.product.idProduct, this.customerId);
    this.subscriptionLotProduct = this.shoppingService
      .getLotProduct(this.product.idProduct, this.customerId)
      .subscribe((lotes) => {
        console.log(JSON.stringify(lotes));
        this.shoppingService.setListLotProduct(lotes);
      }
      );
    //  this.view = this.lotProduct$.pipe(
    //    map((data) => process(data, this.gridState))
    //  );

    // this.view = this.editService.pipe(
    //   map((data) => process(data, this.gridState))
    // );

    //  this.editService.read();

  }

  ngAfterViewInit() {
    this.setFocus(); // If the button is already present...
    this.inputPrice.changes.subscribe(() => {
      this.setFocus();
    });
  }

  setFocus() {
    if (this.inputPrice.length > 0) {
      this.inputPrice.first.nativeElement.focus();
      this.inputPrice.first.nativeElement.select();
    }
  }

  addQuantity(product: SaleProduct) {
    const oldValue = this.form.get('quantity').value;
    let addQuantity = 1;
    if (product.mutiple !== 1) {
      addQuantity = product.mutiple;
    }
    let newValue = (Number.parseFloat(oldValue) + addQuantity);
    if (newValue > product.stock) {
      newValue = oldValue;
    }
    newValue = Number.parseFloat(newValue.toFixed(3));
    this.form.patchValue({ quantity: newValue });
  }

  minusQuantity(product: SaleProduct) {
    const oldValue = this.form.get('quantity').value;
    let addQuantity = 1;
    if (product.mutiple !== 1) {
      addQuantity = product.mutiple;
    }
    let newValue = (Number.parseFloat(oldValue) - addQuantity);
    if (newValue < 0 || newValue < product.mutiple) {
      newValue = product.mutiple;
    }
    newValue = Number.parseFloat(newValue.toFixed(3));
    this.form.patchValue({ quantity: newValue });
  }

  addProductCart(product: any) {
    // this.returnProduct.emit({ ...this.product, quantity: this.formQuantity.get('quantity').value });
  }

  public onConfirmation() {
    console.log('botao acionado');
    this.dialog.close();
  }


  async addProductCard(product: any) {
    const idCart = this.shoppingService.getCart();
    const quantity = this.form.get('quantity').value;
    let quantityBox = Math.trunc((quantity / product.mutiple));
    const quantityArred = (quantityBox * Number.parseFloat(product.mutiple));
    if (quantityArred < quantity) {
      quantityBox = quantityBox + 1;
    }
    const quantitySale = (quantityBox * product.mutiple);
    const descriptionAux = this.form.get('description').value;
    const deliveryType = this.form.get('deliveryType').value;
    const store = this.form.get('store').value;
    const environment = this.form.get('environment').value;
    let price = this.product.listPrice; // Number.parseFloat(this.form.get('price').value);
    //  if (product.base === 'S') {
    if (this.product.salePromotion > 0) {
      price = this.product.salePromotion;
    }
    const newPrice = Number.parseFloat(this.form.get('price').value);
    console.log(`Preço de tabela: ${price} - Novo Preço: ${newPrice} - Promocional: ${this.product.offPercent}`);
    if ((this.updatePrice) && (newPrice < price)) {
      this.messageInformation = 'Preço de venda inválido!';
      this.informationDescription = 'Preço informado não pode ser inferior ao preço de tabela!';
      this.showInformation = true;
      return;
    }
    price = newPrice;


    if (deliveryType === null || deliveryType === '' || deliveryType === undefined) {
      this.messageInformation = 'Não foi informado o tipo de entrega!';
      this.informationDescription = 'Para incluir o item selecione um tipo de entrega para o produto!';
      this.showInformation = true;
      return;
    }

    const initialValue = 0;
    let stockCart = this.shoppingItens.filter(i => i.idProduct === product.idProduct
      && i.stockStore === store)
      .reduce((previousValue, item) => previousValue + (item.quantity),
        initialValue
      );
    if (this.shoppingItem !== undefined && this.shoppingItem !== null) {
      stockCart = stockCart - this.shoppingItem.quantity;
    }
    this.subscriptionStock = this.productService
      .validateStock(product.idProduct, deliveryType, store,
        (quantitySale + stockCart))
      .pipe(
        map((stockValid) => {
          if (stockValid) {
            try {
              this.error = null;
              const id = (this.shoppingItem != null) ? this.shoppingItem.id : null;
              const sellerId = (this.shoppingItem != null) ? this.shoppingItem.seller : this.authService.getSeller();
              const discount = (this.shoppingItem != null) ? this.shoppingItem.discount : null;
              const discountValue = (this.shoppingItem != null) ? this.shoppingItem.discountValue : null;
              const userDiscount = (this.shoppingItem != null) ? this.shoppingItem.userDiscount : null;
              const cost = (this.shoppingItem != null) ? this.shoppingItem.cost : null;
              this.store.dispatch(new AddItemAction({
                id, idCart, invoiceStore: this.authService.getStore(),
                idProduct: product.idProduct, description: product.title, image: product.images[0], productType: product.productType,
                quantity: quantitySale, price, deliveryType, cost: cost,
                stockStore: store, seller: sellerId, percentUpQuantity: 0, upQuantity: 0,
                discount, discountValue, ean: product.ean, promotion: (product.offPercent > 0) ? product.salePrice : 0,
                listPrice: price, userDiscount, mutiple: product.mutiple,
                auxDescription: descriptionAux, smallDescription: product.smallDescription, brand: product.brand,
                base: product.base, letter: product.letter, line: product.line, color: product.color,
                can: product.can, environment: environment
              }));

              this.loading$.subscribe((inProcess) => {
                console.log(inProcess);
                if (this.error) {
                  this.dialog.close({ success: false, message: this.error.message });
                  console.log('Erro ocorrido: ' + JSON.stringify(this.error));
                }
                if (!inProcess && this.error == null) {
                  console.log('Produto incluido com sucesso!');
                  this.dialog.close({ success: true, message: 'Produto incluído com sucesso!' });
                }
              });
            } catch (e) {
              console.log(e);
            }
          } else {
            // mostrar mensagem de falta de estoque
            this.messageInformation = 'Produto sem estoque disponível!';
            this.informationDescription = 'Verifique a disponibilidade do produto em outras filiais de estoque.';
            this.showInformation = true;
          }
        })
      ).subscribe();
  }

  isShowDescription() {
    this.showDescription = !this.showDescription;
    this.textShowMore = (this.showDescription) ? 'Ver menos' : 'Ver mais';
  }

  editingPrice() {
    this.editPrice = !this.editPrice;
    if (!this.editPrice) {
      this.form.patchValue({
        price: this.product.salePrice,
      });
    }
  }

  confirmPrice() {
    const newPrice = Number.parseFloat(this.form.get('price').value);
    let listPrice = this.product.listPrice;
    if (this.product.salePromotion > 0) {
      listPrice = this.product.salePromotion;
    }

    if (newPrice < listPrice) {
      this.form.patchValue({ price: (this.shoppingItem != null ? this.shoppingItem.price : this.product.salePrice) });
      this.messageInformation = 'Preço menor que o preço de tabela!';
      this.informationDescription = 'Preço informado é menor que o preço de tabela, em caso de desconto utilize a função de desconto por item ou pedido.';
      this.showInformation = true;
      return;
    }
    this.salePrice = newPrice;
    this.editPrice = !this.editPrice;
    this.updatePrice = true;
  }

  addQuantityM2() {
    console.log('Adicionar 10%: ' + this.form.get('addUpQuantity').value);
    const isAddPercentQuantity = !(this.form.get('addUpQuantity').value as boolean);
    if (isAddPercentQuantity) {
      const quantityProduct = Number.parseFloat(this.form.get('quantity').value);
      const quantity = Number.parseFloat((quantityProduct * 0.1).toFixed(3));
      let newQuantity = quantityProduct + quantity;
      if (this.product.mutiple > 1) {
        newQuantity = Number.parseFloat((newQuantity / this.product.mutiple).toFixed()) * this.product.mutiple;
        if (newQuantity < (quantityProduct + quantity)) {
          newQuantity += this.product.mutiple;
        }
      }
      newQuantity = Number.parseFloat(newQuantity.toFixed(3));
      this.form.patchValue({
        quantity: newQuantity.toFixed(3),
        originalQuantity: quantityProduct.toFixed(3),
        addUpQuantity: (newQuantity - quantityProduct),
      });
    } else {

      const quantityProduct = Number.parseFloat(this.form.get('quantity').value);
      const quantity = Number.parseFloat((quantityProduct / 1.1).toFixed(3));
      let newQuantity = quantity;
      if (this.product.mutiple > 1) {
        newQuantity = Number.parseInt((newQuantity / this.product.mutiple).toFixed(3), 10) * this.product.mutiple;
      }
      console.log(newQuantity);
      this.form.patchValue({
        quantity: newQuantity.toFixed(2),
        originalQuantity: newQuantity.toFixed(2),
        addUpQuantity: 0,
      });

    }

  }

  calcBoxProduct(product: SaleProduct) {
    const quantityProduct = Number.parseFloat(this.form.get('quantity').value);
    let boxQuantity = (quantityProduct / product.mutiple);
    if ((boxQuantity - Number.parseFloat(boxQuantity.toFixed())) > 0.01) {
      boxQuantity += 1;
    }
    return boxQuantity.toFixed();
  }

  onDialogClose() {
    this.dialog.close();
  }

  openLotProduct() {
    this.shoppingService.getListLotProduct().subscribe(data => this.view = data);
    this.shoppingService.getListLotProduct().subscribe(lotes => this.lotProduct = lotes);
    this.showLotProduct = true;
  }

  public save(dataLotproduct: LotProduct): void {
      Object.assign(
        this.lotProduct.find(({ lotProduct }) => lotProduct === dataLotproduct.lotProduct),
        this.lotProduct
      );
  }

  public onStateChange(state: State): void {
    this.gridState = state;

    this.editService.read();
  }

  public cellCloseHandler(args: CellCloseEvent): void {
    const { formGroup, dataItem } = args;
    console.log(JSON.stringify(formGroup.value));
    if (!formGroup.valid) {
      // prevent closing the edited cell if there are invalid values.
      args.preventDefault();
    } else if (formGroup.dirty) {
      if (args.originalEvent && args.originalEvent.keyCode === Keys.Escape) {
        return;
      }
    }
  }

  public addHandler(args: AddEvent): void {
    // args.sender.addRow(this.createFormGroup(new LotProduct()));
  }


  public saveHandler(args: SaveEvent): void {
    if (args.formGroup.valid) {
      args.sender.closeRow(args.rowIndex);
    }
  }

  public removeHandler(args: RemoveEvent): void {
    //this.remove(args.dataItem);

    args.sender.cancelCell();
  }

  public saveChanges(grid: GridComponent): void {
    grid.closeCell();
    grid.cancelCell();

    this.editService.saveChanges();
  }

  public cancelChanges(grid: GridComponent): void {
    grid.cancelCell();

    this.editService.cancelChanges();
  }

  public saveRow(): void {
    if (this.formGroup && this.formGroup.valid) {
      this.saveCurrent();
    }
  }

  public cellClickHandler({
    isEdited,
    dataItem,
    rowIndex,
  }: CellClickEvent): void {
    if (isEdited || (this.formGroup && !this.formGroup.valid)) {
      return;
    }

    if (this.isNew) {
      rowIndex += 1;
    }

    this.saveCurrent();

    this.formGroup = this.createFormGroup(dataItem);
    this.editedRowIndex = rowIndex;

    this.grid.editRow(rowIndex, this.formGroup);
  }

  public cancelHandler(): void {
    this.closeEditor();
  }

  private closeEditor(): void {
    this.grid.closeRow(this.editedRowIndex);

    this.isNew = false;
    this.editedRowIndex = undefined;
    this.formGroup = undefined;
  }

  private saveCurrent(): void {
    if (this.formGroup) {
      this.save(this.formGroup.value);
      this.closeEditor();
    }
  }


  private onDocumentClick(e: Event): void {
    if (
      this.formGroup &&
      this.formGroup.valid &&
      !this.matches(
        e.target,
        "#productsGrid tbody *, #productsGrid .k-grid-toolbar .k-button"
      )
    ) {
      this.saveCurrent();
    }
  }


}
