// NG imports
import { Component, ElementRef, Input, Renderer2, ViewChild } from '@angular/core'
import { PlatoConfiguratorService } from '../../../../services/svc.plato-configurator'
import { BasketService } from '../../../../services/svc.basket'
import { ActivatedRoute, Params, Router } from '@angular/router'
import { MatDialog, MatDialogRef } from '@angular/material'
import { CompletionDialogComponent } from '../completion-dialog/cmp.completion-dialog'
import { StringifyOptions } from 'querystring'
import { PlatoParams, PLATOProduct } from '@k-core/interfaces/Plato'

// Get scope to determine if production mode is enabled or not
import { scope } from '@k-settings/app-setup.js'
import { server } from '@k-settings/store-helper'


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

export class ConfiguratorComponent {

    @Input('data') data

    // PLATO Configurator version
    version: string = '1.1.179'
    cdn: string = `https://hde-cdn.azureedge.net/libs/components/Configurator/${this.version}`

    jsComponents = [
        `${this.cdn}/main.js`,
        `${this.cdn}/polyfills.js`,
        `${this.cdn}/runtime.js`
    ]
    renderedJs: boolean = false
    products: PLATOProduct[]

    selectedProduct: PlatoParams
    params: PlatoParams

    dialogRef: MatDialogRef<CompletionDialogComponent>
    haslisteners: boolean = false
    @ViewChild('configurator') configuratorWrapper: ElementRef // Should be ElementRef<HTMLDivElement> but its not supported in ng5

    configurationFinished = (e: any) => {

        // Get all information about the product variant which was saved
        this.createProductEntry(e.detail.variant)
    }

    configurationError = (e: any) => {

        // Get all information about the error that has been occurred
        console.error(e, e.detail);
    }

    env = scope == 'production' || scope == 'staging' ? 'prod' : 'acceptance'


    isCopy: boolean = false
    public quantity: number = 1

    accessorySalesItem: any
    tags: any

    tagSet: Set<string | number> = new Set()
    constructor(
        private pcs: PlatoConfiguratorService,
        private renderer: Renderer2,
        private basket: BasketService,
        private router: Router,
        private dialog: MatDialog
    ) {

        // Url structure: /{konfigurator}/type_id/{type_id}/{guid}/{variant}
        const urlArr: string[] = this.router.url.split('/').reverse()

        // Check if URL is longer than 2 and smaller than or equal to 6, to ensure this is only run when type is config
        if(urlArr.length > 2) {

            this.params = {
                guid: urlArr[1],
                variant: urlArr[0]
            }
        }
    }

    ngOnInit() {

        // Gets products
        this.pcs.getCatalog().then(() => {

            this.products = this.pcs.productData.items

            if(this.params) {

                let doesProductExist = this.basket.basket.find((p) => p.id.replace('-PLATO--', '') === this.params.variant)
                
                if(this.params.guid && doesProductExist) {
                    this.productGUID(this.params)
                    
                } else if(this.params.guid && !doesProductExist) {

                    let selectedChild = this.products.find((p) => p.guid === this.params.guid)

                    this.productGUID({
                        type: 'Product',
                        guid: this.params.guid,
                        variant: this.params.variant,
                        image: selectedChild.image,
                        code: selectedChild.code,
                        description: selectedChild.description,
                        copy: true
                    })

                }
            }



            this.pcs.getTags().then((response) => {
                this.tags = response
            })
        })

        // Renders the JS and attaches eventListeners
        document.addEventListener("configurationFinished", this.configurationFinished, true)
        document.addEventListener("configurationFailed", this.configurationError, true)

    }

    ngOnDestroy() {

        document.removeEventListener('configurationFinished', this.configurationFinished, true)
        document.removeEventListener('configurationFailed', this.configurationError, true)
    }

    /**
     * Generates the Configurator
     * 
     * @param product 
     */
    productGUID(product: PlatoParams) {
        this.selectedProduct = product
        this.quantity = 1

        // Set product type if it doesn't exist
        if(!product.type) product.type = 'Product'

        if(product.type === 'Product') {

                // Sets a marginal timeout to wait for the configurators parent to be spawned before spawning
                setTimeout(() => {
        
                    this.configuratorWrapper.nativeElement.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"})
                    
                    // If the HTML element exists, remove it
                    if(document.querySelector('hde-configurator')) {
                        
                        document.querySelector('hde-configurator').remove();
                        (window as any).webpackJsonp = undefined;
                    }
        
        
                    // Build the HTML Element
                    let element: HTMLElement = this.renderer.createElement('hde-configurator')
        
                    // If variant exists, load the configurator with a variant, else load the product as a base
                    if(!!this.params && this.params.variant) {
        
                        this.renderer.setAttribute(element, 'data-productVariantId', this.selectedProduct.variant)
                        this.renderer.setAttribute(element, 'data-productid', this.selectedProduct.guid) // product id
        
                        // Clear params
                        this.params = undefined
                    } else {
                        
                        this.renderer.setAttribute(element, 'data-productid', this.selectedProduct.guid) // product id
                    }
        
                    this.renderer.setAttribute(element, 'bearerToken', this.pcs.impersonatortoken.access_token) // 1st token
                    this.renderer.setAttribute(element, 'apiurl', `${server}configuratorapi/api/configurator/`)
                    this.renderer.setAttribute(element, 'productVariantCommandApiUrl', `${server}variantcommandapi/`)
                    this.renderer.setAttribute(element, 'productVariantQueryApiUrl', `${server}variantqueryapi/`)
                    this.renderer.setAttribute(element, 'localizationApiUrl', 'https://hdestorage.blob.core.windows.net/libs/BMS.DST.Localization/')
                    this.renderer.setAttribute(element, 'localizationFileExtension', '.json')
                    this.renderer.setAttribute(element, 'language', 'da')
                    
                    // Adds the progress bar
                    let progress: HTMLElement = this.renderer.createElement('hde-progress-bar')
                    this.renderer.appendChild(element, progress)
        
                    this.renderer.appendChild(this.configuratorWrapper.nativeElement, element)
        
        
        
                    // Iterates the JS bundles needed, and inserts them in the `main` div
                    for(let component of this.jsComponents) {
        
                        let tag: HTMLScriptElement = this.renderer.createElement('script')
                        this.renderer.setAttribute(tag, 'type', 'text/javascript')
                        this.renderer.setAttribute(tag, 'src', component)
        
                        this.renderer.appendChild(document.querySelector('.main'), tag)
                    }
            
            
                }, 100)
        } else {
            this.getAccessory(product.guid)
        }

    }


    setQuantity(event: number) {
        this.quantity = +event
    }

    public getAccessory(guid: string) {

        this.pcs.getSalesPrice(guid).then((response) => {
            this.accessorySalesItem = response
        })        

    }

    /**
     * Creates a basket entry for an accessory
     */
    public createAccessoryProductEntry() {

        this.dialogRef = undefined


        let object = {
            title: this.selectedProduct.description,
            type: 'PLATO-accessory',
            price: this.accessorySalesItem.salesPrice.unitPrice,
            image: this.selectedProduct.image,
            guid: this.selectedProduct.guid,
            code: this.selectedProduct.code
        }


        this.basket.addProduct(`-dv--${this.selectedProduct.guid}`, this.quantity, object).subscribe({
            complete: () => {
                this.openDialog()   
            }
        })
    }


    /**
     * Creates a product entry in the basket
     * 
     * @param guid 
     */
    createProductEntry(guid: string) {

        this.dialogRef = undefined
        if(this.selectedProduct.variant && this.selectedProduct.copy) {
            guid = this.selectedProduct.variant
        }


        // If guid comes back as an object, skip adding
        if(typeof guid == 'string') {

            this.basket.addProduct(
                `-PLATO--${guid}`,
                this.quantity,
                {
                    title: this.selectedProduct.description,
                    endpoint: 'plato',
                    type_id: this.data,
                    guid: guid,
                    image: this.selectedProduct.image,
                    base: this.selectedProduct.guid,
                    code: this.selectedProduct.code
                })
                .subscribe({
                    complete: () =>  {
                        this.openDialog()
                    },
                    error: (e) => {
                        console.error('error', e)
                    }
                })
        } else {
            this.openDialog()
        }
    }


    /**
     * Toggles dialog open, and afterClosed target defined
     */
    openDialog() {
        this.dialogRef = this.dialog.open(CompletionDialogComponent)
                        
        this.dialogRef.afterClosed().subscribe((r) => {
            if(r) {
                this.dialogRef = null
                this.selectedProduct = undefined
            }
        })
    }

    toggleTag(tag) {
        if(this.tagSet.has(tag)) {
            this.tagSet.delete(tag)
        } else {
            this.tagSet.add(tag)
        }


        if(this.tagSet.size !== 0) {
            this.pcs.getCatalogByTags(Array.from(this.tagSet).toString() + '').then((response) => {
                this.products = response.items
            })
        } else {
            this.products = this.pcs.productData.items
        }
    }
}