// NG imports
import { Component, OnInit, PLATFORM_ID, Inject } from '@angular/core'
import { Location, isPlatformBrowser } from '@angular/common'
import { ActivatedRoute, Params, Router, NavigationEnd } from '@angular/router'


// Interfaces
import { ProductType }          from '@k-core/types/product'
import { ProductService }       from '@k-services/svc.product'
import { HelperService }        from '@k-services/svc.helper'
import { SeoService }           from '@k-services/svc.seo'

// Services
import { Cookie }               from 'ng2-cookies'
import { LocalstorageService } from '@k-services/general/storage'

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


@Component({
    moduleId: module.id+ '',
    selector: 'product-view',
    templateUrl: './tpl.product-view.pug',
    styleUrls: ['./sty.product-view.scss']
})

export class ProductView implements OnInit {


    // ---- Variables ---- \\
    basket: any
    product: ProductType
    parameters: any
    color: string
    descriptions = {}
    displayBlock: any
    quantity: number = 1
    quantityInBasket: number = 0
    
    variant: boolean = false
    price: any = 0
    
    initItem = {
            "Fabric": "",
            "Frame": ""
    }

    // asUnitPrice
    asUnitPrice = false

    // Options interface
    isOptions: boolean = true
    options = new Map
    canAdd: boolean = false

    // Price Tier Interface
    priceTiers = new Map
    priceTier: number = 0

    constructor(
        @Inject(PLATFORM_ID) private _platformId,
        public localStorage: LocalstorageService,
        private _route: ActivatedRoute,
        private _router: Router, // Used in constructor
        private _productService: ProductService,
        private _helper: HelperService,
        private _seo: SeoService,
    ) {
        // Scroll to top 
        _router.events.subscribe(e => {
            if (e instanceof NavigationEnd) {
                this._helper.scrollTo()
            }
        })

        _productService.productHelper$.subscribe(result => {
            this.displayBlock = result;
        })
    }



    // ---- Lifecycle hooks ---- \\
    ngOnInit(): void {

        this._route.params
        .switchMap((params: Params) => this._productService.getProduct(params['productkey']))
        .subscribe(product => {
            this.assignProduct(product)

            // Set SEO
            this._seo.setTitle(product.meta.title);
            this._seo.updateTag('description', (product.meta.description ? product.meta.description: ''))
        })
    }


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


    /**
     * Intercept and manipulate product on load, call functions to
     * draw several values on product
     * 
     * @param product 
     */
    assignProduct(product: any) {

        this.product = product

        if(this.product.product_type == 'configurable') {
            this.canAdd = true
        }

        
        this.setPriceTiers(this.product)
        
        this.getProductQuantity().then((response) => {
            this.quantityInBasket = response
            this.getPriceTier()
        })
    }


    /**
     * Checks if a string contains paragraph, and adds one if none exists
     * 
     * @param text 
     * 
     * @returns string
     */
    addParagraph(text:string) {
        let correctedText = text
        if(!!text) {
            if(text.indexOf('<p>') === -1) {
                correctedText = '<p>' + text + '</p>'
            }
        }
        return correctedText
    }


    /**
     * Sets the configuration of product
     * 
     * @param event 
     */
    setVariation(event) {

        this.product.sku = event.sku
        this.product.price = event.price
        if(event.price_tiers) {
            this.product.price_tiers = event.price_tiers
        }

        this.options.clear()

        for(let attribute of event.attributes) {
            if(attribute.code !== 'product_group')
                this.options.set(attribute.code, attribute.formattedValue)
        }

        this.product.quantity = event.quantity

        this.setPriceTiers(this.product)


        if(!!event.quantity) {
            this.canAdd = false
        } else {
            this.canAdd = true
        }

        this.variant = true
    }
    

    /**
     * Gets the product quantity in basket
     * 
     * @returns number quantity | 0
     */
    getProductQuantity(): any {

        return new Promise((resolve) => {

            if(!!this.localStorage.getItem(AppHelper.cookieName)) {
    
                // Turn the basket into something iterable
                let basket = JSON.parse(this.localStorage.getItem(AppHelper.cookieName))
    
                // If basket exists, find out if product is in basket
                if(basket.length) {

                    let inBasket = basket.some((item) => {
                        return item.id.includes(this.product.sku)
                    })

                    // If the product is in the basket, then find it and return the quantity
                    if(inBasket) {
    
                        let product = basket.find((item) => {
                            return item.id.includes(this.product.sku)
                        })
        
                        resolve(product.quantity)
                    } 
                } else {
                    // If basket doesn't exist, return 0
                    resolve(0)
                }
            }
        })
    }


    /**
     * Re-checks the quantity and checks if there's an update to price tier
     */
    recheckQuantity() {
        this.getProductQuantity().then((response) => {
            this.quantityInBasket = response
            this.getPriceTier()
        })
    }

    /**
     * Update the quantity
     * 
     * @param event 
     */
    updateQuantity(event) {
        this.quantity = event

        this.getPriceTier()
    }


    /**
     * Generates the price tiers Map, which we can then lookup into
     */
    setPriceTiers(product): void {

        if(!!product.price_tiers) {
            for(let tier of product.price_tiers) {
                this.priceTiers.set(tier.quantity, tier)
            }
        }
    }


    /**
     * Looks up into the most recent price tier, based on quantity,
     * sets priceTier to 0 if no price_tiers match
     * 
     * @param quantity 
     */
    getPriceTier(): void {

        // Generate an iteratable from a Map
        let keys = Array.from(this.priceTiers.keys())
        let qty = this.quantity + this.quantityInBasket

        // Checks if quantity matches any keys from the price tier map
        let hasPriceTier = keys.some((key) => {
            return key <= qty
        })

        if(hasPriceTier) {

            // Reversing the array, to find the highest possible match
            let tierPriceKey = keys.reverse().find((key) => {
                return key <= qty ? key : false
            })

            // Turns the price into a float, as it is received as a string
            this.priceTier = parseFloat(this.priceTiers.get(tierPriceKey).price)

        } else {

            // Sets irce tier to 0, if no rules match. This will make original price appear
            this.priceTier = 0
        }
    }
}