// NG imports
import { Injectable, Inject, ApplicationRef, PLATFORM_ID, OnDestroy } from '@angular/core'
import { Location, isPlatformBrowser } from '@angular/common'
import { HttpClient }           from '@angular/common/http'
import { CacheService }         from '@k-core/services/general/svc.cache'

// Additional Libs
import { Cookie } 	            from 'ng2-cookies'
import { isObject }             from 'util'
import { Subject }              from 'rxjs/Subject'
import { Subscription }        from 'rxjs/Subscription'

// Settings
import { AppHelper }            from '@k-settings/app-helper'
import { storeCode }            from '@k-settings/store-helper'

// Types
import { BasketType } from '../types/basket'
import { ProductType } from '../types/product'

// Helpers
import { HelperService } from './svc.helper'
import { ConfiguratorService } from '../modules/configurator/services/svc.configurator'


import { map } from 'rxjs/operators'
import { Observable } from 'rxjs'
import { MatDialog } from '@angular/material'
import { CannotAddDialogComponent } from '@k-core/modules/basket-partial/components/cannot-add-dialog/cmp.cannot-add-dialog'
import { of } from 'rxjs/observable/of'
import { retry, tap } from 'rxjs/operators'
import { LocalstorageService, SessionstorageService } from './general/storage'
import { PlatoConfiguratorService } from './svc.plato-configurator'
import { from } from 'rxjs/observable/from'
import { ActiveCartService } from './active-cart.service'

/**
 * @since >Mon Dec 17 2018
 * @author Kasper Hansen - Klean
 * @description ...
 * ____________________________________
 * @since Mon Dec 17 2018
 * @author Charles Gouldmann - Klean
 * ____________________________________
 * @since Wed Nov 13 2019
 * @author Kasper Hansen
 * @description Created a new checker for add Product that contains a verification of productGroup being the same across all added products. Disallow ability to add sync and async products to same order
 * ____________________________________
 * @since Mon Jan 27 2020
 * @author Kasper Hansen
 * @description Added more logic to an already convoluted service... we need a Klean-up on this, it's a mess, KREATE is handling the same task in >200 lines
 */

@Injectable()
export class BasketService {

    storeCode: string = storeCode
    productTypes: string = undefined

    // Attribute order
    public attr = [
        {name: 'marking', order: 1},
        {name: 'type_id', order: 2},
        {name: 'width', order: 3},
        {name: 'height', order: 4},
        {name: 'a', order: 6},
        {name: 'b', order: 7},
        {name: 'c', order: 8},
        {name: 'd', order: 9},
        {name: 'angle', order: 10},
        {name: 'MountType', order: 20},
        {name: 'mountPosition', order: 21},
        {name: 'mountHeights', order: 22},
        {name: 'customChain', order: 23},
        {name: 'color-family', order: 30},
        {name: 'dessin', order: 31},
    ]


    // ---- Variables ---- \\

    // Private Variables
    private key: string         = this.helper.credentials
    private api: string         = this.helper.server+'feed/get'
    private productApi: string  = this.api + '/product' + this.key
    private cartApi: string     = this.helper.server + 'feed/set/cart'
    private cookieName: string  = AppHelper.basketIdentifier
    private basketContent: BasketType[]
    private priceMap = new Map
    private basketWatch
    private basketWatchDiff: boolean = false // loop breaker, not used for now

    attribute = new Map
    isAttributesMapped = new Map
    steps = {}
    // Public Variables
    public basketSource = new Subject<BasketType[]>()
    public basket$ = this.basketSource.asObservable()
    public basket: BasketType[]
    
    public attributeSource = new Subject<any>()
    public attribute$ = this.attributeSource.asObservable()

    private mappedProductsSource = new Subject<any>()
    public mappedProducts$ = this.mappedProductsSource.asObservable()

    private stepSource = new Subject<any>()
    public step$ = this.stepSource.asObservable()

    // Subscriptions
    private subscriptions = new Subscription()


    constructor(
        @Inject(PLATFORM_ID) private platformId: Object,
        public localStorage: LocalstorageService,
        public sessionStorage: SessionstorageService,
        private _cache: CacheService,
        private http: HttpClient,
        private helper: HelperService,
        private _config: ConfiguratorService,
        private _dialog: MatDialog,
        private pcs: PlatoConfiguratorService,
        private activeCart: ActiveCartService
    ) {
        // init subscriptions
        this.subscriptions.add(
            this.mappedProducts$.subscribe(result => {
                this.isAttributesMapped = result
            })
        )

        this.subscriptions.add(
            this.basket$.subscribe(result => {
                this.basketContent = result
            })
        )

        this.step$.subscribe((res) => {
            this.localStorage.setItem('steps', JSON.stringify(res))
        })


        if(isPlatformBrowser(this.platformId)) {

            // Checks to see if basket exists and is valid JSON - returns it to set as Observable or blank Array[] depending on result
            this.basket = ((this.localStorage.getItem(this.cookieName) && this.isValidJson(this.localStorage.getItem(this.cookieName))) ? JSON.parse(this.localStorage.getItem(this.cookieName)) : [] )
            this.setObject(this.basket)

            if(!!this.basket.length) {

                let skuProducts = this.basket.filter((p) => p.id.includes('-sku') || p.id.includes('-conf'))

                if(!skuProducts.find((p) => p.id.includes('AUTOGEN'))) {
    
                    let skuProductList = this.basket.filter((product) => product.id.includes('sku') || product.id.includes('conf'))
                    if(skuProductList.length) {
    
                        this.http.get(this.api + '/product-group' + this.key + '&sku=' + skuProductList[0].id.replace('-sku--', '') + '&noCache')
                            .pipe(
                                map((response: any) => {
                                    return response.data.value
                                })
                            )
                            .subscribe((type) => {
                                if(!this.productTypes) {
        
                                    if(!!type) {
        
                                        this.productTypes = type
                                    } else {
                                        this.productTypes = this.sessionStorage.getItem('storedProductType')
                                    }
                                }
                            })
                    }
    
                }
            }

            
        }

        // start watch
        this.watchBasket()

        if(isPlatformBrowser(this.platformId)) {
            if(!!this.localStorage.getItem('steps')) {
                this.steps = JSON.parse(this.localStorage.getItem('steps'))
            }
        }
    }




    
    // ---- Lyfecycle hooks ---- \\

    ngOnDestroy() {
        this.subscriptions.unsubscribe()
        clearInterval(this.basketWatch)
    }






    // ---- Functions ---- \\

    //* Private Functions

    /**
     * Error handler
     * 
     * TODO: Make a real error handler
     * 
     * @param error 
     */ 
    private handleError(error: any): Promise<any> {
        return Promise.reject(error.message || error);
    }    


    /**
     * Check if string is valid json
     * 
     * @param {string} str
     * @returns {boolean}
     */ 
    private isValidJson(str: string): boolean {
        try {
            var o = JSON.parse(str);
            if (o && typeof o === "object") {
                return true;
            }    
        }     
        catch (e) { }
        return false;
    }    



    /**
     * ! Describe
     * 
     * @param item 
     */
    private findType(item) {


        let value = item.id.split('--')[0]

        let result: any = {
            type: '',
            sku: ''
        }

        switch(value.toLowerCase()) {
            case '-conf':

                result.type = 'configurable'
                result.sku = 'curtain'
            break

            case '-plato':
                result.type = 'plato'
                result.sku = item.data.guid

                break;

            case '-dv':

                result.type = 'diverse'
                result.sku = 'misc'
            break

            case '-cu':
            case '-ir':

                result.type = 'individual-discount'
                result.sku = 'id'
            break

            case '-sku':

                result.type = 'SKU'
                result.sku = item.id.split('--')[1]

            break
            case '-key':
            case '-info':
                result.type = 'INFO'

            break

            default:
                console.error('Type: ' + value + '  is not defined, please define type and try again <DEVELOPER>')
            break
        }


        return result
    }


    /**
     * Starts a interval that runs a compare
     */
    private watchBasket() {
        if(isPlatformBrowser(this.platformId)) {
            this.basketWatch = setInterval(() => this.compareAndUpdateBasket(), 1000)
        }
    }

    /**
     * Will compare the local storage basket and the current basket. 
     * If they are different the localstorage basket will be used.
     * 
     * If no localstorage is found, client basket is assumed incorrect and reset
     */
    private compareAndUpdateBasket() {
        if(isPlatformBrowser(this.platformId)) {
            let localstorageItem = this.localStorage.getItem(AppHelper.basketIdentifier)

            if(!!localstorageItem) {
                let localBasket = JSON.parse(localstorageItem)

                if(this.basketContent.toString() !== localBasket.toString()) {

                    this.basket = localBasket
                    this.basketSource.next(localBasket)
                }
            
            // Reset if basket has content and local storage does not
            } else if(!!this.basketContent && !!this.basketContent.length) {
                this.basket = []
                this.basketSource.next([])
            }
        }
    }






    //* Public Functions

    /**
     * Get the id and quantity of items in basket
     * 
     * *! Will default to localstorage
     * 
     * @returns {BasketType[]} products
     */
    public getBasketProducts(useLocal: boolean = false): BasketType[] {

        let products: BasketType[] = []

        if(this.basketContent && useLocal) {
            products = this.basketContent
        }
        else {
            if(isPlatformBrowser(this.platformId)) {

                // if cookie is not set return (default) empty array
                if(!!this.localStorage.getItem(AppHelper.basketIdentifier)) {
                    products = JSON.parse(this.localStorage.getItem(AppHelper.basketIdentifier))
                    this.basketSource.next(products)
                }
            }
        }

        return products
    }


    /**
     * Set Observable to element called (generally, cookie)
     * @param element
     * @returns {void}
     */
    public setObject(element): any {

        return new Promise((resolve) => {

            this.basketSource.next(element)
            resolve(true)
        })
    }


    /**
     * Used to set and delete cookie and observable in 1 action
     * @param value 
     * @param rule
     * @returns {void}
     */
    public updateObject(value, rule): void {


        if(isPlatformBrowser(this.platformId)) {

            
            switch (rule) {
                case 'delete':
                    this.basketSource.next(value)
                    this.localStorage.removeItem(this.cookieName)
                    this.basket = value
                    
                    this.http.get(this.helper.server + '/feed/set/closecart' + this.helper.credentials)
                    .toPromise()
                    .then(() => {
                        this.activeCart.getActiveCartLink()
                    })
                    break


                case 'set':
                    this.basketSource.next(value)
                    this.localStorage.setItem(this.cookieName, JSON.stringify(value))
                    
                    this.basket = value

                    break


                default:
                    console.warn('Rule for updateObject() not set! Please fix')
                    break
            }
        }   
    }



    /**
     * Get Product Info
     * 
     * TODO: Add a local "cache" to filter through before calling API
     * TODO: Possibly add this function to product service
     * 
     * @param id: number
     * @returns {Promise<ProductType[]>}
     */
    public getProductById(id:number): Promise<ProductType> {

        return this.http.get(this.productApi+'&extend&sku='+id)
            .toPromise()
            .then((response: any) => {
                return response.data.product as ProductType
            })
            .catch(this.handleError);
    }


    /**
     * Adds a product (or discount) to cart with SKU and Quantity
     * Saves in both Observable and Cookie
     * 
     * TODO: It seems there is a bug here where items are pushed on update.
     * 
     * @param id: any 
     * @param quantity: number
     * @returns {string}
     */
    public addProduct(id: any, quantity: number, data: any = {}): Observable<string> {

        // Intercept and stop further execution
        if(id.includes('AUTOGEN'))
            return of(this._addProductToBasket(id, quantity, data))

        if(id.includes('-conf--') || id.includes('-sku--')) {

            const sku = id.includes('-conf-') ? data.sku : id.replace(/(-).+(--)/gi, '')
            
            return this.http.get(`${this.api}/product-group${this.key}&sku=${sku}&noCache`)
            .pipe(
                map((response: any) => { // TODO: Type
                    return response.data.value
                }),
                map((type: string) => {

                    // If type is undefined, set it to 7
                    if(type === undefined) type = '7'

                    // If productTypes doesn't exist, fix that and add the product, else only add products where they match
                    if(!this.productTypes) {

                        

                        this.sessionStorage.setItem('storedProductType', type)
                        this.productTypes = type
                        return this._addProductToBasket(id, quantity, data)
    
                    } else {
    
                        if(type == this.sessionStorage.getItem('storedProductType')) {
                            return this._addProductToBasket(id, quantity, data)
                        } else {
                            this._dialog.open(CannotAddDialogComponent)
                            return 'error'
                        }
                    }
                })
            )
        } else {
            
            return of(this._addProductToBasket(id, quantity, data))
        }
    }


    //! This seems wrong
    public getAttributeMap() {
        this.attributeSource.next(this.attribute)
    }


    /**
     * ! Describe
     * 
     * @param item 
     * @param object 
     */
    private attributeMap(item, object) {
        for(let element of Object.keys(item)) {

            if(!isObject(item[element])) {

                    if((isNaN(object[element]))) {
                        
                        this.attribute.set(item[element], object[element])
                    }

            } else {

                for(let subObject of Object.keys(item[element])) {

                    if(!!object[element] && isNaN(object[element][subObject]))
                        this.attribute.set(item[element][subObject], object[element][subObject])
                }
            }
        }

        this.attributeSource.next(this.attribute)
    }




    /**
     * Populates a `BasketItem` from backend and maps the attributes to `mappedProductSource`
     * Also requests price, and populates that into `priceMap`
     * TODO: Split up into more functions and make more readable, @Kasper
     * 
     * @param item 
     */
    public getBasketItem(item): Promise<any> {

        const prefix = item.data.sku === 'curtain' || !('sku' in item.data) ? '' : `${item.data.sku}-`

        // Gets the labels and saved the mapped state of product, so it doesn't run more than once
        if(!this.isAttributesMapped.get(item.id)) {
            this._config.requestLabel(item.data).then((response: any) => {

                this.attributeMap(item.data, response.data.attributes)
                this.mappedProductsSource.next(this.isAttributesMapped)
                
            }) 
        } else {

            this.isAttributesMapped.set(item.id, true)
            this.mappedProductsSource.next(this.isAttributesMapped)
        }
        

        if(!!item.data) {


            return new Promise((resolve, reject) => {
                
                if(this.priceMap.has(item.id)) {

                    // Find the type of the item
                    let types = this.findType(item)

                    item.sku = !item.sku ? item.data.sku : item.sku

                    // Create return object
                    let object = {
                        type: types.type,
                        sku: !item.sku ? types.sku : item.sku,
                        id: item.id,
                        type_id: (item.data.type_id ? item.data.type_id : ''),
                        price: this.priceMap.get(item.id),
                        quantity: item.quantity,
                        options: []
                    }



                    // Flatten options before exposing them
                    for(let key of Object.keys(item.data)) {
                        let value = item.data[key]

                        if(isObject(value)) {

                            for(let subkey of Object.keys(value)) {
                                let val = value[subkey]

                                // Slightly magic-stringy
                                object.options.push({code: subkey, value: val})
                            }



                        } else {
                            object.options.push({code: key, value: value})
                        }
                    }
                    
                    resolve(object)

                } else {



                    let promise = new Promise(resolve => {
                        resolve(this._config.requestPrice(item.data))
                    }).then((price: any) => {
                        this.priceMap.set(item.id, price.data.price)
                        
                        new Promise(resolve => {
                            resolve(this.findType(item))

                        }).then((response: any) => {

                            
                            let types = response

                            item.sku = !item.sku ? item.data.sku : item.sku

                            let object = {
                                type: types.type,
                                sku: !item.sku ? types.sku : item.sku,
                                id: item.id,
                                type_id: item.data.type_id,
                                price: this.priceMap.get(item.id),
                                quantity: item.quantity,
                                options: []
                            }
                            
                            // Flatten options before exposing them
        
                            for(let key of Object.keys(item.data)) {

                                let value = item.data[key]
                                if(isObject(value)) {
        
                                    for(let subkey of Object.keys(value)) {
                                        let val = value[subkey]
        
                                        // If the key is conditions, name it instead of naming it '0' and put the value into an array of objects, else set the option 1:1 as a subkey
                                        if(key == 'conditions') {

                                            subkey = key
                                            object.options.push({code: subkey, value: [val]})

                                        } else {
                                            object.options.push({code: subkey, value: val})
                                        }
                                    }
        
                                } else {

                                    object.options.push({code: key, value: value})
                                }
                            }

                            // If condition doesn't exist, and aggregator does, create condition with a blank array
                            if(!object.options.find(option => option.code == 'conditions') && object.options.find(option => option.code == 'aggregator')) {
                                object.options.push({code: 'conditions', value: []})
                            }

                            resolve(object)
                        })
                        
                    })
                }

            })

        } else {
            
            return new Promise(resolve => {
                resolve(this.getProductById(item.id))
            })
        }
    }



    /**
     * POST to backend for active rules
     * ! WARNING: You cannot add caching to this, it breaks functionality. 
     * ! DEPRECATION WARNING: THIS SHOULD BE REMOVED! Handled within the Common module: CommonDiscountServices
     */
    public getDiscounts():Promise<any> {

        let requestActiveCartRules = {
            key: this.helper.apiKey,
            storeId: this.helper.storeId,
            websiteId: this.helper.websiteId,
            noCache: true,
            cart: this.basket
        }



        return this.http.post(this.helper.server + '/feed/get/active-cart-rules', requestActiveCartRules).toPromise().then((response: any) => {

            return response
        })
    }


    /**
     * Gets all basket items and returns them as product data
     * 
     * @param basket: Object<generic> 
     * @returns {Promise<ProductType[]>}
     */
    public getBasketItems(basket): Promise<ProductType[]> {

        return new Promise((resolve) => {
            let basketItems: any = [];

            let productPromises = basket.map((item) => {

                return this.getProductById(item.id);
            });

            Promise.all(productPromises)
                .then((results) => {

                    results.forEach(function(product) {
                        basketItems.push(product);
                    });
            
                    resolve(basketItems);
                });
        });
    }


    /**
     * ! Describe
     * 
     * @param sku 
     */
    getResultPrice(sku) {


        if(this.priceMap.has(sku) && this.priceMap.get(sku) !== false) {

            return new Promise(resolve => {
                resolve(this.priceMap.get(sku))
            }).then((response) => {
                return response
            })
        }

        else {

            return this.http.get(`${this.productApi}&sku=${sku}&fields:price`).toPromise().then((response: any) => {
                if(response.status == 'error') {
                    throw response
                }
                else {
                    return response.data.product.price
                }
            })
        }

    }


    /**
     * Empties Observable and Cookie
     * 
     * @returns {void}
     */
    public emptyBasket(): void {
        
        this.basket = []
        
        // Keep trying until window exists
        let int = setInterval(() => {
            
            if (typeof window !== 'undefined') {
                
                clearInterval(int) 
                this.sessionStorage.clear()
                                
                if(isPlatformBrowser(this.platformId)) {
                    window.localStorage.clear()
                }
                
                this.updateObject([], 'delete')

                setTimeout(() => {

                    this.productTypes = undefined
                }, 1000)
            }
        }, 100)
    }


    /**
     * Remove product from basket by SKU
     * 
     * @param id: number
     * @returns {void}
     */
    public removeProductFromBasket(id: any): void {
        if(isPlatformBrowser(this.platformId)) {

            let basket = JSON.parse(this.localStorage.getItem(this.cookieName))
            
            // Look through basket and find product position
            let product = basket.findIndex(item => item.id == id)
            
            // Only remove an element if its found
            if(product >= 0) {
                // remove element in product position, then update basket$
                basket.splice(product, 1)
    
                console.log(basket, product)
    
                this.updateObject(basket, 'set');
            }
        }
    }


    
    /**
     * Gets the quantity of an item within the basket
     * 
     * @param id: number
     * @returns {number}
     */
    public getQuantityInBasket(id:any): number {
        
        // Get newest data from Observable, to ensure this does not fail out.
        let basket = this.basketContent
        let result = 0;

        // Find product in basket
        let product = basket.find(function(item) {
            return item.id === id;
        })

        // Only return product.quantity if product is set
        // Avoids error in log, doesn't do anything other than "clean"
        // Try-catch does not work in this case.

        if(!!product) {
            result = product.quantity
        }

        // Return quantity of product
        return result;
    }



    /**
     * Updates the quantity of an item in Basket
     * 
     * @param id: number
     * @param quantity: number
     * @returns {void}
     */
    public updateBasketQuantity(id:number, quantity:number): void {

        new Promise((resolve) => {
            for (var product in this.basket) {
                if (this.basket[product].id == id) {
                    this.basket[product].quantity = quantity;
                    resolve(true)
                    break
                }
            }
        }).then(() => {
            // update saved basket
            if (typeof window !== 'undefined') { // make sure window exists
                this.updateObject(this.basket, 'set')
            }
        })

    }


    /**
     * Adds or updates a product with a generic setup
     * Only works with an expected cartProduct format.
     * 
     * @param basketItem 
     */
    public addOrUpdateProduct(basketItem) {

        // Define a function to run through and format the basketItem into a BasketItem
        const defineBasketItem = (item) => {

            let options = {}
            item.options.forEach((v) => options[v.code] = v.value)

            return {
                id: item.id,
                quantity: item.quantity,
                data: options
            }
        }

        let item = this.basket.find((item) => item.id === basketItem.id)
        
        // Check if the item already exists within the basket, if it does, delete it
        if(item) {
            this.basket.splice(this.basket.findIndex((item) => item.id === basketItem.id), 1)
        }

        // Add basket (back) into the cart, and update caches
        this.basket.push(defineBasketItem(basketItem))
        this.localStorage.setItem(this.cookieName, JSON.stringify(this.basket))
        this.basketSource.next(this.basket)
    }



    /**
     * ! Describe
     * 
     * 
     * @param id 
     * @param attribute 
     * @param value 
     */
    public updateBasketItemValue(id, attribute, value) {
        for(let product in this.basket) {
            if(this.basket[product].id == id) {
                
                let element = this.basket[product].data


                if(!!element[attribute]) {
                    element[attribute] = value
                } else {
                    // TODO: Make a loop to go deeper, not needed for this iteration
                }

                
            }
        }

        this.updateObject(this.basket, 'set')
    }



    public destroyObservable() {
        this.basketSource.next([])
    }



    /**
     * Sets cart and posts it to PHP Checkout
     * 
     * @returns {Promise<any>} result
     */
    public setCart(cart, custom):Observable<any> {

        let object = {
            'key': this.helper.apiKey,
            'storeId': this.helper.storeId,
            'websiteId': this.helper.websiteId,
            'cart': cart,
            'store': this.storeCode.replace('kirsch', 'suntex'), // TODO: FIX THIS!!!!
            'localstorage': JSON.parse(this.localStorage.getItem(AppHelper.basketIdentifier)),
            'clear': true
        }

        for(let key of Object.keys(custom)) {
            object[key] = custom[key]
        }


        return this.http.post(this.cartApi, object)
            .pipe(
                retry(5)
            )
    }

    
    public addStep(identifier, quantity) {

        this.steps[identifier] = quantity
        this.stepSource.next(this.steps)
    }

    /**
     * Set a unique key if none exists in the basket, generates this as a promise chain, to resolve several keys being initialized at once
     */
    public setKey() {

        new Promise((resolve) => {

            let basketProducts = []

            let interval = setInterval(() => {
                
                if(basketProducts.length == 0) {

                    basketProducts = this.getBasketProducts()

                } else {

                    clearInterval(interval)
                    resolve(basketProducts)

                }
            }, 100)

        }).then((basket: any) => {

            // Ensure the element does not start with -key--
            return basket.find((item) => {
                return item.id.indexOf('-key--') > -1
            })

        }).then((hasKey) => {

            // Set key if none exist
            if(!hasKey) {
                let uniqueId = Date.now() + '-' + Math.random().toString(36).substr(2, 10) + Math.random().toString(36).substr(2, 10)

                if (typeof window !== 'undefined') {
                    this.basket.push({id: '-key--' + uniqueId, quantity: 0, data: {string: 'im here to make sure you have a good time :)'}});
                    this.updateObject(this.basket, 'set')   
                }
            }
        })
    }


    /**
     * TODO: Clean up.
     * 
     * @param id 
     * @param quantity 
     * @param data 
     */
    private _addProductToBasket(id: any, quantity: any, data: any = {}): string {
        // Look for product in basket
        let filteredBasket: any

        if(isPlatformBrowser(this.platformId)) {

            // Pull the newest from cookie, to ensure we're not destroying existing setups
            if(this.localStorage.getItem(this.cookieName)) {
                this.basket = JSON.parse(this.localStorage.getItem(this.cookieName))
            }
        }
        
        if(this.basket) {
            filteredBasket = this.basket.filter((p) => {
                    return id === p.id
                }
            )[0]
        }

        // If Product is already in basket, add quantity to current product
        if(filteredBasket) {
            filteredBasket.quantity = parseInt(filteredBasket.quantity) + parseInt(quantity)

            this.updateObject(this.basket, 'set')

        } else {

            this.basket.push({id, quantity, data})
            if (typeof window !== 'undefined') { // make sure window exists
                this.updateObject(this.basket, 'set')
                
            }

        }
        
        return 'success'
    }


    /**
     * Gets the PLATO product
     * 
     * @param guid 
     * @returns 
     */
    getPlatoProduct(guid: string) {
        return from(this.pcs.getVariant(guid))
    }

    copyPlatoProduct(guid: string) {
        return from(this.pcs.copyVariant(guid))
    }
}