/**
 * Made by mkcomponent.sh
 * * Change to Fileheader info *
*/

// Core imports
import { Component, OnInit } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { NgForm } from '@angular/forms'

// Services
import { HelperService } from '@k-services/svc.helper'
import { SendCartService } from '../../services/svc.send-cart'
import { SendCartFactory } from '../../services/fac.send-cart'
import { DiscountsService } from '@k-core/common/discount/services/svc.discounts'
import { Subscription } from 'rxjs'
import { tap } from 'rxjs/operators'

// Interfaces
interface ShippingMethod {
    amount: number;
    carrier_code: string;
    carrier_title: string;
    has_pickup: boolean;
    message: string;
    method_code: string;
    method_title: string;
    pickup_list_url?: string;

}
interface Store {
    address: string;
    city: string;
    country: string;
    entity_id: string;
    label: string;
    latitude: string;
    longitude: string;
    pickup_identifier: string;
    store_code: string;
    updated_at: string;
    url: string;
    zip: string;
}

interface Store {
    address: string;
    city: string;
    country: string;
    entity_id: string;
    label: string;
    latitude: string;
    longitude: string;
    pickup_identifier: string;
    store_code: string;
    updated_at: string;
    url: string;
    zip: string;
}

enum EDiscountType {
    none        = 'none', 
    percentage  = 'percentage', 
    flat        = 'flat'
}



/**
 * @name ShippingComponent
 * @description Generates a list of all shipping methods and displays them
 * @author Kasper Hansen
 * @since 07-01-2019
 */ 

@Component({
    moduleId: module.id+ '',
    selector: 'send-cart-shipping',
    templateUrl: './template/t--shipping.pug',
    styleUrls: ['sty.shipping.scss']
})

export class ShippingComponent implements OnInit {

    // ---- Variables ---- \\
    shippingMethods: any
    postcode: string = ''
    selected: string = undefined
    overlayStores: any[]
    setOverlay: boolean = false
    setError: boolean = false
    selectedLocation: any = undefined
    currentlySelectedMethod: any
    firstDiscount: boolean = true

    // Logic
    discountValue: number = 0
    discountType: EDiscountType = EDiscountType.none

    // Subscriptions
    private _subscriptions = new Subscription()





    constructor(
        private _helper: HelperService,
        private _http: HttpClient,
        private _discount: DiscountsService,
        private _sendCart: SendCartService,
        private _factory: SendCartFactory
    ) {


        /**
         * Get discount and assign value to discount variables
         */
        this._subscriptions.add(
            // ... Type it...
            _discount.mountDiscount$.distinctUntilChanged().subscribe((result: any) => {


                if(!!result) {
                    // Set discount amount  
                    this.discountValue = result.options.find(option => option.code == 'price').value
                    
                    // Set discount type
                    let discountType = result.options.find(option => option.code == 'type').value
                    let typeValue = result.options.find(option => option.code == 'ruleData').value

                    if(typeValue) {
                        
                        let type = typeValue.action

                        // If the disocuntType comes back as mount, enforce that value is calculated as percentage
                        if(discountType !== 'mount')
                            type = discountType.split('mount_')[1]

                        switch (type) {
                            case 'percent':
                            case 'percent_of_base':
                            case 'by_percent_of_base':
                            case 'percentage':
                            case 'percentage_of_base':
                            case 'by_percentage_of_base':
                                this.discountType = EDiscountType.percentage
                                break
    
                            case 'fixed':
                            case 'fixed_of_base':
                            case 'by_fixed_of_base':
                                this.discountType = EDiscountType.flat
                                break
                        
                            default:
                                this.discountType = EDiscountType.percentage
                                break
                        }
                    }



                } else {
                    this.discountValue = 0
                }

                if(!!this.currentlySelectedMethod)
                    this.setMethod(this.currentlySelectedMethod.displayName, this.currentlySelectedMethod.type, this.currentlySelectedMethod.cost)
            })
        )



        _factory.getShippingMethods().pipe(tap((response) => {
            if(!response) {
                this._sendCart.nullifyShipping()
                throw 'shippingMethod not defined'
            }
        })).subscribe((response: any) => {

            if(response.quote.activeShippingMethods.length) {

    
                // Generates a collected carrier code for correct comparison
                for(let method of response.quote.activeShippingMethods) {
                    method.carrier_code = (method.carrier_code + '_' + method.method_code != method.carrier_code ? method.carrier_code + '_' + method.method_code : method.carrier_code)
                }
    
                this.shippingMethods = response
                let active_methods = response.quote.activeShippingMethods
    
                // Sets data from sessionStorage if value exists
                new Promise((resolve) => {
                    
                    resolve(this._sendCart.sessionStore('get'))
                }).then((response) => {
    
                    let shipping_method = response['shippingMethod']
    
                    if(!!shipping_method) {
    
                        // Set selected
                        this.selected = shipping_method.method
    
                        // set the shipping method
                        this.setSelectedShippingMethod(active_methods, shipping_method.method)
    
    
                        if(!!shipping_method.store) {
                            this.selectedLocation = shipping_method.store
    
                            // Set postcode
                            if( !!shipping_method.store.zip) {
                                this.postcode = shipping_method.store.zip
                            }
    
                            // set the shipping method and store
                            this.setSelectedShippingMethod(active_methods, shipping_method.method, shipping_method.store)
                        }
                        else {
                            // set the shipping method
                            this.setSelectedShippingMethod(active_methods, shipping_method.method)
                        }
    
                    }
                })  
            } else {
                this._sendCart.nullifyShipping()
            }
        })
    }


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

        this._sendCart.cart$.subscribe((response) => {

            if(this.postcode.length == 0) {
                if(!!response.shippingAddress && !!response.shippingAddress.postcode) {
                    this.postcode = response.shippingAddress.postcode
                } else if(!!response.billingAddress && !!response.billingAddress.postcode) {
                    this.postcode = response.billingAddress.postcode
                }
            }
        })
    }


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

    /**
     * Finds selected method in shipping methods and sets method if found.
     * Store is also set if given.
     * 
     * @param shippingMethods 
     * @param selectedMethod
     * @param store
     * 
     * @requires setMethod()
     */
    setSelectedShippingMethod(shippingMethods: ShippingMethod[], selectedMethod: string, store?: Store) {

        for(let s_method of shippingMethods) {
            
            if(s_method.carrier_code === selectedMethod) {
                

                this.setMethod(s_method.carrier_title, s_method.carrier_code, s_method.amount)

                if(!!store) {
                    this.selectStore(store, store.store_code)
                }
            }
        }
    }


    /**
     * Sets the method based on `displayName`, `type` and `cost`
     * then posts is to the `sessionStore` and to the `cart`
     * Also toggles `selected` on the element
     * 
     * @param displayName 
     * @param type 
     * @param cost 
     */
    setMethod(displayName, type, cost) {

        this.selected = type
        let originalCost = cost

        let setElement = {
            method: this.selected
        }

        this._sendCart.sessionStore('set', 'shippingMethod', setElement)

        this.currentlySelectedMethod = {'type': type, 'displayName': displayName, 'cost': originalCost}

        this._sendCart.setShipping(type, displayName, cost)
    }


    /**
     * Finds and pulls all `data.locations` matching the given `element.zip`
     * then displays a list of all `locations` or an `error`
     * 
     * @param form 
     * @param requestUrl 
     */
    onSubmit(form: NgForm, requestUrl) {

        this.setError = false

        this._http.get(requestUrl + '&zip=' + this.postcode).toPromise().then((response: any) => {
            let data = response.data.locations

            new Promise((resolve) => {
                resolve(this._helper.filter_array(data))
            }).then((response: any[]) => {

                this.overlayStores = response

                if(this.overlayStores.length > 0)
                    this.setOverlay = true
                else
                    this.setError = true
            })

        })
    }


    /**
     * Sets the specific selected store, identified by `id`, fills the `store` info into `sessionStore` and `cart`
     * 
     * @param store 
     * @param id 
     */
    selectStore(store, id) {
        
        this.setOverlay = false
        this.selectedLocation = store
        
        let setElement = {
            method: this.selected,
            store: this.selectedLocation
        }
        
        this._sendCart.sessionStore('set', 'shippingMethod', setElement)
        this._sendCart.setExtendedShipping(this.selectedLocation)
    }
}
