import { ChangeDetectorRef, Component, Input, OnInit, AfterViewInit, OnDestroy, ElementRef, Output, ViewChild, EventEmitter} from '@angular/core';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { HttpErrorResponse } from '@angular/common/http';

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

// Interfaces
import { SessionDataInterface } from 'src/app/interfaces/session-data-interface';

// Services
import { SessionService } from 'src/app/services/session/session.service';
import { AccountInfoService } from 'src/app/services/accountInfo/account-info.service';

import { ModalConfig } from 'src/app/interfaces/common-interfaces';

import { EditPaymentMethodModalComponent } from 'src/app/components/edit-payment-method-modal/edit-payment-method-modal.component';

// Stripe
import { loadStripe, Stripe, StripeElements, StripePaymentElement } from '@stripe/stripe-js';
import { environment } from 'src/environments/environment';
@Component({
    standalone: false,
    selector: 'stripe-payment-model',
    templateUrl: './stripe-payment-model.component.html',
    styleUrls: ['./stripe-payment-model.component.scss']
})
export class StripePaymentModelComponent implements OnInit, AfterViewInit {
    @Input() stripePaymentModel!: NgbModalRef
    @Input() stripePaymentModelNo!: () => void
    @Input() paymentMethodCards!: any;
    @Input() paymentMethodBank!: any;
    @Input() pendingBankPymentMethods!: any;
    @Input() isFromCart: boolean = false;
    @Input() forSupp!: any;
    @Output() addPayMethodStatus = new EventEmitter<{status : boolean, addNewPaymentId : string | null}>();
    @Output() deletePaymentMethod = new EventEmitter<string | null>();
    @ViewChild('deleteConfirmModal') deleteConfirmModal !: ElementRef;
    paymentMethodsSubscribe!:Subscription;
    resultSubscribe!:Subscription;
    delPayMethodSubscribe!:Subscription;
    openPayMethodsDiv = false;
    isloading = false;
    verifyLink = '';
    accordText!: any;
    session!: SessionDataInterface['data'];
    isBuyer!: boolean;
    paymentMethodId: string | null = null;
    deletePaymentMethodId!: any;
    stripe: Stripe | null = null;
    elements: StripeElements | undefined;
    paymentElement!: StripePaymentElement | null;
    
    statusMessage: string | null = null;
    deleteErrorMsg: string = "";
    statusType: 'success' | 'error' | null = null;
    constructor(
        private accountInfoService: AccountInfoService,
        private sessionService: SessionService,
        private elementRef: ElementRef,
        private modalService: NgbModal,
        private cdr: ChangeDetectorRef
    ) { }

    ngOnInit(): void {
        this.session = this.sessionService.getSession();
        this.isBuyer = this.session.is_buyer;
    }
    
    /**
     * Angular lifecycle hook called after component's view has been fully initialized.
     * Initializes Stripe, retrieves the client secret, and mounts the Stripe Payment Element.
     * Handles and logs any errors during initialization.
     */
    async ngAfterViewInit(): Promise<void> {
        try {
            this.stripe = await loadStripe(environment.stripePublicKey);
            // Use your Angular service to get the clientSecret
            const response: any = await firstValueFrom(this.accountInfoService.createSetup());
            
            const clientSecret = response?.data?.clientSecret;

            if (!this.stripe || !clientSecret) throw new Error('Stripe setup failed');

            this.elements = this.stripe.elements({ clientSecret });

            this.paymentElement = this.elements.create('payment', {
              layout: { type: 'tabs' },
              readOnly: false,
              wallets: { link: 'never' },
              paymentMethodOrder: [
                'us_bank_account',
                'card'
              ]
            });

            this.paymentElement.mount('#payment-element');
            if (this.isFromCart) {
                this.accountInfoService
                    .trackAddNewPayMethodEvent()
                    .pipe(
                        catchError(() => {
                            return throwError(() => new Error('ups something happened'));
                        })
                    )
                    .subscribe({
                        next: (res: any) => {
                        },
                        error: (err: HttpErrorResponse) => {
                          this.accountInfoService.errorCallBack(err);
                        },
                        complete: () => { }
                    });
            }

        } catch (error) {
            console.error('Error initializing Stripe:', error);
        }
    }
  
    /**
     * Handles the Stripe payment method setup form submission.
     * Confirms the setup intent with Stripe, emits the result status, and dismisses the modal on success.
     * Emits false and logs an error if setup fails.
     */
    async onSubmit(): Promise<void> {
        if (!this.stripe || !this.elements) return;
        this.isloading = true;
        this.verifyLink = '';
        this.deleteErrorMsg = "";
        this.paymentMethodId = '';
        const result = await this.stripe.confirmSetup({
            elements: this.elements,
            confirmParams: {
              return_url: window.location.href,
            },
            redirect: 'if_required'
        });
        if (result.error) {
            this.addPayMethodStatus.emit({status : false, addNewPaymentId : ''});
            this.statusMessage = result.error.message || 'Setup failed. Please try again.';
            this.statusType = 'error';
            this.isloading = false;
            return;
        }
        if (result.setupIntent && (result.setupIntent.status === 'succeeded' || result.setupIntent.status === "requires_action")) {
            // Setup succeeded
            this.statusMessage = 'Payment method added successfully!';
            this.statusType = 'success';
            const pm = result.setupIntent.payment_method;
            this.paymentMethodId = typeof pm === 'string' ? pm : null;
            if (result.setupIntent.status === "requires_action") {
                this.isloading = false;
                
                if (result.setupIntent?.next_action?.verify_with_microdeposits?.hosted_verification_url) {
                    this.verifyLink = result.setupIntent.next_action.verify_with_microdeposits.hosted_verification_url;
                    
                    this.accountInfoService
                        .savePayMethodInfo(this.paymentMethodId, this.verifyLink)
                        .pipe(
                            catchError(() => {
                                this.statusMessage = 'Error saving bank payment method!';
                                this.statusType = 'error';
                                this.isloading = false;
                                return throwError(() => new Error('ups something happened'));
                            })
                        )
                        .subscribe({
                            next: (res: any) => {
                                this.fetchPaymentMethods();
                                this.addPayMethodStatus.emit({status : true, addNewPaymentId : this.paymentMethodId});
                                this.statusMessage = "Account has been added, Please click on below link to complete verification process.";
                                this.statusType = 'success';
                                firstValueFrom(this.accountInfoService.createSetup()).then((response: any) => {
                                    const newClientSecret = response?.data?.clientSecret;
                                    if (!this.stripe || !newClientSecret) {
                                        console.error('Failed to get new client secret');
                                        return;
                                    }

                                    // reinitialize elements with new clientSecret
                                    this.elements = this.stripe.elements({ clientSecret: newClientSecret });
                                    this.paymentElement = this.elements.create('payment', {
                                        layout: { type: 'tabs' },
                                        readOnly: false,
                                        wallets: { link: 'never' },
                                        paymentMethodOrder: [
                                            'us_bank_account',
                                            'card'
                                        ]
                                    });
                                    this.paymentElement.mount('#payment-element');
                                });
                            },
                            error: (err: HttpErrorResponse) => {
                              this.accountInfoService.errorCallBack(err);
                            },
                            complete: () => { }
                        });
                    
                } else {
                    this.statusMessage = "Account has been added, Please click on below link to complete verification process.";
                    this.statusType = 'success';
                }
            } else {
                firstValueFrom(this.accountInfoService.createSetup()).then((response: any) => {
                    const newClientSecret = response?.data?.clientSecret;
                    if (!this.stripe || !newClientSecret) {
                        console.error('Failed to get new client secret');
                        return;
                    }

                    // reinitialize elements with new clientSecret
                    this.elements = this.stripe.elements({ clientSecret: newClientSecret });
                    this.paymentElement = this.elements.create('payment', {
                        layout: { type: 'tabs' },
                        readOnly: false,
                        wallets: { link: 'never' },
                        paymentMethodOrder: [
                            'us_bank_account',
                            'card'
                        ]
                    });
                    this.paymentElement.mount('#payment-element');
                });
                setTimeout(() => {
                    this.statusMessage = '';
                }, 2000);
                setTimeout(() => {
                    this.fetchPaymentMethods();
                    this.isloading = false;
                    if (!this.openPayMethodsDiv) {
                        this.togglePaymentMethods();
                    }
                    this.addPayMethodStatus.emit({status : true, addNewPaymentId:this.paymentMethodId});
                }, 1500);
            }
            if (this.isFromCart && this.forSupp != null) {
                this.delPayMethodSubscribe = this.accountInfoService.delCartUserSuppPayMethod(this.forSupp)
                    .subscribe({
                      next: () => {
                          this.fetchPaymentMethods();
                          if (this.isFromCart) {
                              this.deletePaymentMethod.emit(this.paymentMethodId);
                          }
                      },
                      error: (err: HttpErrorResponse) => {
                        this.accountInfoService.errorCallBack(err);
                      },
                      complete: () => { },
                    })
            }
        }
    } 

    /**
     * Opens the Stripe payment modal for setting up a payment method.
     * Subscribes to the addPayMethodStatus event to update the payment method status.
     */
    editPaymentModal!: NgbModalRef
    openEditPaymentModal(method: any) {
        this.deleteErrorMsg = "";
        this.editPaymentModal = this.modalService.open(EditPaymentMethodModalComponent,{size: 'sm'});
        this.editPaymentModal.componentInstance.editPaymentModal = this.editPaymentModal;
        this.editPaymentModal.componentInstance.closeEditPaymentModal = this.closeEditPaymentModal;
        this.editPaymentModal.componentInstance.paymentMethod = method;
        this.editPaymentModal.componentInstance.fetchPaymentMethods = this.fetchPaymentMethods;
        
        this.editPaymentModal.componentInstance.closeEditPaymentModal = () => {
           this.editPaymentModal.dismiss();
           this.fetchPaymentMethods();
           if (this.isFromCart) {
               this.addPayMethodStatus.emit({status : true, addNewPaymentId : ''});
           }
        };
    };

    closeEditPaymentModal() {
        this.editPaymentModal.dismiss();
    }
    
    
    verify(url: any) {
        window.open(url, '_blank', 'noopener,noreferrer');
        this.stripePaymentModelNo();
    }
    /**
     * retrieve all stripe payment methods
    */
    fetchPaymentMethods() {
        this.paymentMethodsSubscribe = this.accountInfoService
        .getAllPaymentMethods()
        .subscribe({
            next: (res: any) => {
                if (res.data !== false) {
                  this.paymentMethodCards = res.data.cards;
                  this.paymentMethodBank = res.data.bankAccounts;
                  this.pendingBankPymentMethods = res.data.pendingBankPayMethods;
                }
                this.cdr.detectChanges();
            },
            error: (err: HttpErrorResponse) => {
              this.accountInfoService.errorCallBack(err);
            },
            complete: () => { }
        });
    }
    
    /**
     * Toggles display payment methods div
    */
    togglePaymentMethods() {
        this.deleteErrorMsg = "";
        this.openPayMethodsDiv = !this.openPayMethodsDiv;
        if (this.openPayMethodsDiv) {
            this.accordText = "&minus;";
        } else {
            this.accordText = "&plus;";
        }
    }

    /*
    * Private Property for base modal config for delete confirmation modal
    */
    deleteConfirmModalConfig:ModalConfig = {
      showHeader: true,
      title: ""
    };

    /**
     * Private method to show  delete confirmation modal
     * @returns void
     */
    deleteConfirmModalSub!:NgbModalRef;
    deletePaymentModal(paymentMethodId:string) {
        this.deleteConfirmModalConfig.title = "";
        this.deleteConfirmModalSub = this.modalService.open(this.deleteConfirmModal, {size: 'sm'});
        this.deletePaymentMethodId = paymentMethodId;
    };

    /*
    * Method to close confirmation modal
    */
    deleteModalClose () {
        this.deleteConfirmModalSub.close();
    };

    /**
     * Remove Payment Method action
    */
    removePaymentMethod(paymentMethodId:string) {
        const payload = {
        'paymentMethodId' : paymentMethodId
      };
      this.deleteErrorMsg = "";
      this.resultSubscribe = this.accountInfoService.deletePaymentMethod(payload)
      .subscribe({
        next: (res: any) => {
            if (res.data.success === true) { 
                this.deleteModalClose();
                this.fetchPaymentMethods();
                if (this.isFromCart) {
                    this.deletePaymentMethod.emit();
                }
            } else {
                this.deleteModalClose();
                this.deleteErrorMsg = res.data.message;
            }
        },
        error: (err: HttpErrorResponse) => {
          this.accountInfoService.errorCallBack(err);
        },
        complete: () => { },
      })
    }

    ngOnDestroy(): void {
        this.paymentMethodsSubscribe?.unsubscribe();
        this.resultSubscribe?.unsubscribe();
        this.delPayMethodSubscribe?.unsubscribe();
    }
}
