// Angular Core
import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, SimpleChanges, ViewChild, ViewChildren } from '@angular/core';

// RxJs
import { catchError, Subscription, throwError } from 'rxjs';

// Services
import { OrdersService } from 'src/app/services/orders/orders.service';
import { SessionService } from 'src/app/services/session/session.service';
import { ManagePurchaseService } from '../../services/manage-purchase.service';
import { UtilitiesService } from 'src/app/services/utilities/utilities.service';

// Components
import { MessagesModalComponent } from '../messages-modal/messages-modal.component';
import { ReOrderItemsModalComponent } from '../re-order-items-modal/re-order-items-modal.component';
import { ResubmitPaymentModalComponent } from '../resubmit-payment-modal/resubmit-payment-modal.component';
import { PedigreeInfoComponent } from 'src/app/components/pedigree-info/pedigree-info.component';

// Interfaces
import { userManagePurchaseInterface } from 'src/app/interfaces/user/user-managePurchases-interface';
import { SessionDataInterface } from 'src/app/interfaces/session-data-interface';
import { ModalConfig } from 'src/app/interfaces/common-interfaces';

// Third Party
import { NgbModal, NgbModalConfig, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { environment } from 'src/environments/environment';

@Component({
  standalone: false,
  selector: 'app-purchases-tab',
  templateUrl: './purchases-tab.component.html',
  styleUrls: ['./purchases-tab.component.scss']
})
export class PurchasesTabComponent implements OnInit, OnDestroy {

  @ViewChild('requestModal') requestModal!: ElementRef;
  @ViewChild('pedigreeInformationModal') pedigreeInformationModal!: ElementRef;
  updateOrderMessages = new EventEmitter<userManagePurchaseInterface['data']['purchase_result'][0]>();

  @Input() data !: userManagePurchaseInterface['data']['purchase_result']; // TODO: type
  @Input() allowed_status !: boolean; // TODO: type
  imgUrl: string = environment.imageUrl;
  session!: SessionDataInterface['data'];
  customerSupport!:string;

  constructor(
    private orders: OrdersService,
    private managePurchaseService: ManagePurchaseService,
    private modalService: NgbModal,
    private elementRef: ElementRef,
    private ngbModalconfig: NgbModalConfig,
    private utilitiesService: UtilitiesService,
    private sessionService : SessionService,
    ) { 
      // customize default values of modals used by this component tree
      this.ngbModalconfig.backdrop = 'static';
      this.ngbModalconfig.keyboard = false;
    }

  purchasesData!: userManagePurchaseInterface['data']['purchase_result'];
  msgLengthError:string = '';
  isUserAllowed!:boolean;
  isCollapsed:boolean[] = [];
  disablePayBtn: any = {};

  ngOnInit(): void {
    this.session = this.sessionService.getSession();
    this.customerSupport = this.session.trxade_number;
    /*
    * Introduced below condition as per TRX-7634.
    * If the isUserAllowed false, the logged-in user is considered to be an admin-level 8 user.
    * If the isUserAllowed true, the logged-in user is considered to be not an admin-level 8 user.
    */
    if (this.allowed_status) {
      this.isUserAllowed = true;
    } else {
      this.isUserAllowed = false;
    }
  }

  /*
  * Pass purchases data to scope to use it in the template.
  */
  ngOnChanges(changes: SimpleChanges) {
    if ('data' in changes) {
      this.purchasesData = changes['data'].currentValue;
    }
  }

  /**
  * Method to Calculate Order total
  * excludes item for calculation  which has the status Item Cancelled(21) or Unaccepted(3)
  * @param {type} items
  * @returns {Number}
  */
  getOrderTotal (items: userManagePurchaseInterface['data']['purchase_result'][0]['items']) {
    var total = 0;
    var excludeStatusArr = [3, 21];
    items.forEach( (item: userManagePurchaseInterface['data']['purchase_result'][0]['items'][0]) => {
      if (excludeStatusArr.indexOf(item.flag_status) === -1) {
        total += item.bid_amount * item.quantity_offered;
      }
    })
    return total;
  };

  /*
  * Private Property for base modal config for Request Modal
  */
  requestModalConfig = {
    showHeader: true,
    title: '',
  };
  requestModalInfo!: NgbModalRef;
  requestModalClose () {
    this.requestModalInfo.close();
  };
  
  orderRequestInfoSubscribe!:Subscription;
  /**
  * send Request for Pedigree or tracking Information
  * @param {type} requestType
  * @param {type} sellerId
  * @param {type} orderId
  * @returns {undefined}
  */
  requestModalMessage!:string;
  sendRequest (requestType: string, sellerId: number, orderId: number, requestFlag: number, supplierName: string) {
    this.requestModalConfig.title = requestType+" request sent";
    if(requestFlag) {
        this.orderRequestInfoSubscribe = this.orders.orderRequestInfo(requestType, sellerId, orderId, '', this.requestModalMessage) // TODO check requestModalMessage
        .pipe(
          catchError(() => {
            return throwError(() => new Error('ups sommething happend'));
          })
        )
        .subscribe({
          next: () => {
            this.requestModalMessage = "A request for "+requestType+" has been succesfully sent to "+supplierName+".\n\
                                      Please allow up to 24 hours before "+requestType+" may be available.";
            this.managePurchaseService.updateManagePurchases.emit({});
          },
          error: (err) => {
            this.orders.errorCallBack(err);
          },
          complete: () => { },
        })
    }
    else {
        this.requestModalMessage = "A request for "+requestType+" has been already sent.\n\
                        Please wait 24 hours before trying again.";
    }
    this.requestModalInfo = this.modalService.open(this.requestModal, {size: 'sm'})
  };

  /**
  * Method to determine if Request Tracking Button should be shown or not
  * @param {type} items
  * @returns {Boolean}
  */
  showTrackingButton (items: userManagePurchaseInterface['data']['purchase_result'][0]['items']) {
    var emptyTracking = 0;
    items.forEach((item: userManagePurchaseInterface['data']['purchase_result'][0]['items'][0]) => { 
      if(item.trackingNumbers.length > 0) {
        emptyTracking++;
      }
    })
    if(emptyTracking === 0) {
        return false;
    }
    return true;
  };

  /**
  * Method to get Tracking Url
  * @param {type} trackingNumber
  * @param {type} trackingRegX
  * @returns {String}
  */
  getTrackingUrl (trackingNumber: string, trackingRegX: {url: string, reg: RegExp}[]) {
    var url = '';
    trackingRegX.forEach((postalService: {url: string, reg: RegExp}) => {
      if(trackingNumber.match(postalService.reg)) {
        url = postalService.url;
      }
    })
    return url;
  };

  /**
  * Provides tracking url in new tab
  * @param {type} trackingNumber
  * @returns {undefined}
  */
  goToTrackingUrl (trackingNumber: number | string) {
    var url = '';
    var trackingRegX = this.orders.trackingUrlExpressions();
    var tracking = String(trackingNumber);
    url = this.getTrackingUrl(tracking,trackingRegX);
    if(!url && tracking.charAt(0) === '0') {
      tracking= tracking.replace(/^0+/, '');
      url = this.getTrackingUrl(tracking,trackingRegX);
    }
    if(url) {
      window.open(url+tracking, '_blank')
    }
  };

  /**
  * Checks If Order Is Processed
  * @param {type} items
  * @returns {Boolean}
  */
  checkIfOrderIsProcessed (items: userManagePurchaseInterface['data']['purchase_result'][0]['items']) {
    let count = 0;
    items.forEach((item: userManagePurchaseInterface['data']['purchase_result'][0]['items'][0]) => {
      if(((item.status).indexOf('Processed')) !== -1) {
        count++;
      }
    });
    return (count > 0);
  };

  /**
  * Update Paid Status of an order
  * @param {type} orderId
  * @param {type} sellerId
  * @param {type} paidStatus
  * @returns {undefined}
  */
  updatePaidStatus (orderId:number, sellerId:number, paidStatus: number | undefined | string) {
    this.orderRequestInfoSubscribe = this.orders.orderRequestInfo('OrderPaymentStatus', sellerId, orderId, paidStatus, '')
    .pipe(
      catchError(() => {
        return throwError(() => new Error('ups sommething happend'));
      })
    )
    .subscribe({
      next: () => {
      },
      error: (err) => {
        this.orders.errorCallBack(err);
      },
      complete: () => { },
    })
  };

  /*
  * Private Property for base modal config for messagesModal
  */
  messagesModalConfig = {
    showHeader: false
  };
  messagesModalInfo!: NgbModalRef;
  /**
  * Private property to set the status of messagesModal
  * @type boolean
  */
  messagesModalOpened: boolean = false;
  messagesModalClose() {
      this.msgLengthError = '';
      this.messagesModalOpened = false;
  };

  /**
   * Method that determines that sets the read flag for messages
   * @param {type} order
   * @returns {undefined}
   */
  readMessages (order: userManagePurchaseInterface['data']['purchase_result'][0]) {
    this.getMessages(order);
    if(order.unread_messages) {
        this.orderRequestInfoSubscribe = this.orders.orderRequestInfo('ReadMessage', 0, order.order_id, '', '')
          .pipe(
            catchError(() => {
              return throwError(() => new Error('ups sommething happend'));
            })
          )
          .subscribe({
            next: () => {
              this.managePurchaseService.updateManagePurchases.emit({});
            },
            error: (err) => {
              this.orders.errorCallBack(err);
            },
            complete: () => { },
          })
    }
  };


  /**
   * Gets all the messages for an order
   * @param {type} order
   * @returns {undefined}
   */
  messageHistory:any[] = [];
  getMessages(order: userManagePurchaseInterface['data']['purchase_result'][0]) {
    this.orderRequestInfoSubscribe = this.orders.orderRequestInfo('GetMessageHistory', 0, order.order_id, '', '')
    .pipe(
      catchError(() => {
        return throwError(() => new Error('ups sommething happend'));
      })
    )
    .subscribe({
      next: (res: any) => {
        this.messageHistory = res.data;
      },
      error: (err) => {
        this.orders.errorCallBack(err);
      },
      complete: () => { 
        if(!this.messagesModalOpened) {
            this.messagesModalOpened = true;
            this.messagesModalInfo = this.modalService.open(MessagesModalComponent, {size: 'lg'});
            this.messagesModalInfo.componentInstance.headerTitle = order.supplier_name;
            this.messagesModalInfo.componentInstance.currentOrder = order;
            this.messagesModalInfo.componentInstance.messageHistory = this.messageHistory;
            this.messagesModalInfo.componentInstance.msgLengthError = this.msgLengthError;
            this.messagesModalInfo.componentInstance.isUserAllowed = this.isUserAllowed;
            this.messagesModalInfo.componentInstance.messagesModalOpened = this.messagesModalOpened;
            this.messagesModalInfo.componentInstance.reply = this.reply;
            this.messagesModalInfo.componentInstance.orders = this.orders;
            this.messagesModalInfo.componentInstance.updateOrderMessages = this.updateOrderMessages;
            this.messagesModalInfo.componentInstance.messagesModalClose = this.messagesModalClose;
    
            this.messagesModalInfo.shown.subscribe(() => {
              this.messagesModalOpened = true;
            })
    
            this.messagesModalInfo.closed.subscribe(() => {
                this.messagesModalOpened = false;
            })
        }
        this.messagesModalInfo.componentInstance.messageHistory = this.messageHistory;
      },
    })
  };

  /**
   * Listener to updateOrderMessages.
   */
  updateOrderMessagesListener = this.updateOrderMessages.subscribe({
    next: (res: userManagePurchaseInterface['data']['purchase_result'][0]) => {
      this.getMessages(res);
    }
  })

  //Unbind data to avoid memory leak
  ngOnDestroy(){
    this.updateOrderMessagesListener?.unsubscribe();
    this.orderRequestInfoSubscribe?.unsubscribe();
  }

  /**
   * Sends the message typed by the pharmacy
   * @param {type} messageText
   * @param {type} order
   * @returns {undefined}
   */
  reply (messageText:string, order: userManagePurchaseInterface['data']['purchase_result'][0]) {
    this.msgLengthError = '';
    if (messageText === undefined || messageText === null || messageText === "" || messageText.length < 3 || messageText.length > 250) {
        this.msgLengthError = "Minimum 3 and Maximum 250 characters allowed.";
        return false;
    } else {
      this.orderRequestInfoSubscribe = this.orders.orderRequestInfo('SendMessage', order.seller_id, order.order_id, '', messageText)
      .pipe(
        catchError(() => {
          return throwError(() => new Error('ups sommething happend'));
        })
      )
      .subscribe({
        next: () => {
          this.updateOrderMessages.emit(order);
        },
        error: (err) => {
          this.orders.errorCallBack(err);
        },
        complete: () => { },
      })
      return true;
    }
  };

  /**
  * Private property to set the status of supplierPedigreeInfo modal
  * @type boolean
  */
  supplierPedigreeInfoOpened:boolean = false;

  /**
   * Private property to store base-modal config
   * @type Object
   */
  supplierPedigreeInfoConfig: {showHeader: boolean, title: string} = {
    showHeader: true,
    title: 'Pedigree Information'
  };


  /**
   * Private method to show the supplierPedigreeInfo modal
   * @returns null
   */
  supplierPedigreeInfoModal!: NgbModalRef;
  showSupplierPedigreeInfoModal () {
    if(!this.supplierPedigreeInfoOpened) {
      this.supplierPedigreeInfoModal = this.modalService.open(PedigreeInfoComponent, {size: 'sm'});
      this.supplierPedigreeInfoModal.componentInstance.supplierName = this.supplierName;
      this.supplierPedigreeInfoModal.componentInstance.supplierPedigreeInfoConfig = this.supplierPedigreeInfoConfig;
      this.supplierPedigreeInfoModal.componentInstance.pedigreeInformation = this.pedigreeInformation;
      this.supplierPedigreeInfoModal.componentInstance.supplierPedigreeInfoModal = this.supplierPedigreeInfoModal;
      this.supplierPedigreeInfoModal.componentInstance.supplierPedigreeInfoClickOk = this.supplierPedigreeInfoClickOk;
      this.supplierPedigreeInfoModal.shown.subscribe(() => {
        this.supplierPedigreeInfoOpened = true;
      })

      this.supplierPedigreeInfoModal.closed.subscribe(() => {
          this.supplierPedigreeInfoOpened = false;
      })
    }
  };


  /**
   * Public method click ok in supplierPedigreeInfo modal
   * @return {undefined}
   */
  supplierPedigreeInfoClickOk() {
    this.supplierPedigreeInfoModal.close();
  };

  /**
   * Method to open Pedigree Information Modal
   */
  pedigreeInformation!:string;
  supplierName!:string;
  supplierPedigreeInfo(supplier: userManagePurchaseInterface['data']['purchase_result'][0]) {
    this.pedigreeInformation = supplier.pedigree_information;
    this.supplierName = supplier.supplier_name;
    this.showSupplierPedigreeInfoModal();
  };

  /**
   * Method to toggle view button
   */
  clickToToggle (orderId:number) {
      const anchorEle: HTMLElement = this.elementRef.nativeElement.querySelector(`a[id='${orderId}_a']`);
      setTimeout(() => {
        anchorEle.click();
      });
  };

  updatePaidStatusCheckbox(order: userManagePurchaseInterface['data']['purchase_result'][0], event:any){
    let paidStatus = Number((event.target.value === 'false' || event.target.value === '0'));
    this.updatePaidStatus(order.order_id, order.seller_id, paidStatus);
  }

   /*
    * Private Property for base modal config for reOrderModalConfig
    */
    reOrderModalConfig:ModalConfig = {
     showHeader: false,
     title: ""
    };

    /**
    * Display Reorder Modal popup
    * @param {object} orderItems
    * @returns void
    */
    reOrderModalSub!:NgbModalRef;
    displayReOrderModal(orderItems: any) {
      this.reOrderModalConfig.title = "";
      this.reOrderModalSub = this.modalService.open(ReOrderItemsModalComponent, {size: 'sm'});
      this.reOrderModalSub.componentInstance.reOrderModalSub = this.reOrderModalSub;
      this.reOrderModalSub.componentInstance.orderItems = orderItems;
      this.reOrderModalSub.componentInstance.reOrderModalClose = () => {
        this.reOrderModalClose();
      };
    };

    /*
     * Method to close re-order modal
    */
    reOrderModalClose() {
       this.reOrderModalSub.close('ok');
    };

    /**
     * Decides if 'FRI' must be displayed before
     * cut off time and returns that string.
     * @param {String} purchaseDate
     * @returns {String}
     */
    showDay(purchaseDate: string) {
        return this.utilitiesService.showDay(purchaseDate);
    };
    
    /**
     * Calculates how many shipping-related icons should be displayed for a given item.
     *
     * This function checks three conditions:
     *  - `is_refrigerated`: whether the item requires refrigeration.
     *  - `is_hazardous`: whether the item is classified as hazardous.
     *  - `ndcGround`: whether the item is restricted to ground shipping only.
     *
     * @param {any} item
     * @returns {number}
     */
    getImageCount(item: any): number {
      let count = 0;
      if (item.is_refrigerated === 1) count++;
      if (item.is_hazardous === 1) count++;
      if (item.ndcGround !== '' && item.ndcGround !== null) count++;
      return count;
    }

    /*
    * Private Property for base modal config for resubmitModalConfig
    */
    resubmitModalConfig:ModalConfig = {
     showHeader: false,
     title: ""
    };

    /**
    * Display resubmit Modal popup
    * @returns void
    */
    resubmitModalSub!:NgbModalRef;
    displayResubmitModal(order: any, payType: any) {
      this.resubmitModalConfig.title = "";
      this.resubmitModalSub = this.modalService.open(ResubmitPaymentModalComponent, {size: 'lg'});
      this.disablePayBtn[order.order_id] = true;
      this.resubmitModalSub.componentInstance.order = order;
      this.resubmitModalSub.componentInstance.payType = payType;
      this.resubmitModalSub.componentInstance.resubmitModalClose = () => {
        this.disablePayBtn[order.order_id] = false;
        this.resubmitModalClose();
      };
    };

    /*
     * Method to close resubmit modal
    */
    resubmitModalClose() {
       this.resubmitModalSub.close('ok');
    };
    
    /**
     * Determines whether the "Resubmit Payment" button should be shown for an order.
     * @param order
    */
    shouldShowResubmitButton(order: any) {
        const isFailed = ['failed', 'server error'].includes(order.payment_status?.toLowerCase() ?? '');
        const isValidPaymentType = order.stripe_payment_type === 'card' || order.stripe_payment_type === 'us_bank_account';
        const canResubmit =((order.resubmit_attempt === 0 || (order.resubmit_attempt > 0 && order.resubmit_attempt % 3 !== 0)) && order.resubmit_payment === 0) || order.resubmit_pmt_reset_by_admin === 1;
        return isFailed && isValidPaymentType && canResubmit;
    };
    
}
