// NG Imports
import { Component, OnInit, OnChanges, Inject, Input, ViewChild } from '@angular/core'
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'

// Components
import { StatusComponent } from '../status/cmp.status'

// Material
//import { MatTableDataSource, MatSort } from '@angular/material'
import { MatDialog } from '@angular/material'

// Libraries
import { Angular2Csv } from 'angular2-csv/Angular2-csv'
import { isObject } from 'util'

// Pipes
import { TranslatePipe }    from '@k-core/pipes/pipe.translate'

// Services
import { SearchOrderService } from '../../services/svc.search-orders'
import { tap } from 'rxjs/operators'
import { Subscription } from 'rxjs'


// Interfaces
interface IOrder {
    address: string;
    amount: number;
    bus: string;
    costprice: number;
    customer: any;
    date: string;
    discount: number;
    id: string;
    integrations: any;
    is_inactive: boolean;
    link: string;
    name: string;
    prices: any;
    quote_id: string;
    ref: string;
    retailer: string;
    retailer_stores: string;
    sender: any;
    status: string;
    telephone: string;
    type: string;
} 


/**
 * @name ListComponent
 * @description *watdo?*
 * @author Kasper-san-sensei san 
 * @since the beginning of time.. or a little later
 * @extends
 */
@Component({
    moduleId: module.id+ '',
    selector: 'search-orders-list',
    templateUrl: './template/t--list.pug',
    styleUrls: ['sty.list.scss']
})


// constructor(breakpointObserver: BreakpointObserver) {
//     breakpointObserver.observe([
//       Breakpoints.HandsetLandscape,
//       Breakpoints.HandsetPortrait
//     ]).subscribe(result => {
//       if (result.matches) {
//         this.activateHandsetLayout();
//       }
//     });
//   }

export class ListComponent {


    // ---- Variables ---- \\
    // Inputs
    @Input('user') user: any

    
    // Data
    orders: IOrder[]
    sortedOrders: IOrder[]
    undisplayables = new Map
    expandedIds = []
    // Settings
    /**
     * Presets select, valid values: type | amount | date | name | address | telephone | ref | bus
     */
    sortOrder: string = 'date'
    columnsToDisplay = ['delete', 'type', 'date', 'customer', 'receipt', 'ref', 'bus', 'retailer', 'comments', 'status']
    sortDirectionDefaults = [
        {name: 'type', order: 'ASC'}, 
        {name: 'name', order: 'ASC'}, 
        {name: 'address', order: 'ASC'}, 
        {name: 'bus', order: 'ASC'}, 
        {name: 'retailer', order: 'ASC'}, 
        {name: 'ref', order: 'ASC'}
    ]


    // Logic
    lastSort: string
    sortingDirection: string = 'DESC'
    
    
    // Angular Material
    //@ViewChild(MatSort) sort: MatSort
    //dataSource: MatTableDataSource<IOrder> = new MatTableDataSource()




    showKPIs: boolean = false
    showOrders: boolean = false
    isHandheld: boolean = false
    tabletExtendedIds = []

    subscriptions = new Subscription()

    constructor(
        public breakpointObserver: BreakpointObserver,
        private _searchOrders: SearchOrderService,
        private _translate: TranslatePipe,
        private _dialog: MatDialog
    ) {

        this.subscriptions.add(
            breakpointObserver.observe([
                Breakpoints.Tablet,
                Breakpoints.Handset

            ]).subscribe((result) => {

                if(result.matches) {
                    this.isHandheld = true
                } else {
                    this.isHandheld = false
                }
            })
        )


        // Gets data from observable, then sorts it, handled within a promise so code doesnt try to sort before data is completely set

        this.subscriptions.add(

            _searchOrders.orders$
            .pipe(
                tap((() => {
                    this.lastSort = ''
                }))
            )
            .subscribe((orders) => {
    
                console.log(orders)

                //this.dataSource.data = orders as IOrder[]
                this.orders = orders
                this.setSortOrder(this.sortOrder)
    
                // new Promise(resolve => {
                //     this.orders = orders
                //     resolve(this.orders)
                // }).then(() => {
    
                //     // Clear the last sort on new search
                //     this.lastSort = ''
                    
                //     // Start new sort
                    
                // })
    
            })
        )

        this.subscriptions.add(

            _searchOrders.searchOptions$.subscribe((result) => {
                this.showKPIs = (result.KPIs ? true : false)
                this.showOrders = (result.orders ? true : false)
            })
        )
    }



    // ---- Lifecycle hooks ---- \\
    ngOnInit() {
        for(let rights of this.user.search_hide) {
            this.undisplayables.set(rights, true)
        }
    }


    ngOnDestroy() {
        this.subscriptions.unsubscribe()
    }
    // Used to set Material sort
    // ngAfterViewInit() {
    //     this.dataSource.sort = this.sort
    // }

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


    /**
     * Changes sort order based on fed value. Can handle Date, Numbers and strings.
     * Will also sort results in `ASC` or `DESC` direction based on defaults in `sortDirectionDefaults`. 
     * If `sort` is not found in defaults `DESC` will be the defualt sorting direction.
     * 
     * @param sort - The name of the column to sort
     * @requires changeSortDirection() `𝑓`
     * @requires orders `var`
     * @requires lastSort `var`
     * @requires sortedOrders `var`
     * @requires sortDirectionDefaults `var`
     */
    setSortOrder(sort: string) {

        // Allows the sort to be changed and applied on data receive
        if(!!this.orders) {

            // If the same sort string is given, reverse order
            if(!!this.sortedOrders && sort === this.lastSort) {
                this.changeSortDirection()
            }
            else {

                // Set the sortOrder, and last sort
                this.sortOrder = sort
                this.lastSort = sort
    
                // Copy un-mutated orders
                this.sortedOrders = Array.from(this.orders)

                // Sort orders
                this.sortedOrders.sort((a, b) => {
        
                    // As return is the same for price and date, set value in if, then return it as `-`
                    if(sort == 'date' || sort == 'receipt' || sort == 'comments') {
    
                        let a_value: any
                        let b_value: any
                        
                        // Filter for specific rules, for number comparison
                        switch(sort) {
                            case 'date':
                                    a_value = this.changeDateToLocaleString(a[sort])
                                    b_value = this.changeDateToLocaleString(b[sort])

                                    return a_value - b_value

                            case 'receipt':

                                    a_value = a.prices.total
                                    b_value = b.prices.total

                                    return a_value - b_value


                            case 'comments':

                                    a_value = (!!a.integrations.commentAmount ? a.integrations.commentAmount : 0)
                                    b_value = (!!b.integrations.commentAmount ? b.integrations.commentAmount : 0)

                                    return a_value - b_value

                            default:

                                a_value = a[sort]
                                b_value = b[sort]

                                return a_value - b_value


                        }

    
                        
    
                    } else {

                        let a_value: string
                        let b_value: string


                        // Filter for specific rules, for string comparison
                        switch(sort) {

                            case 'customer':

                                a_value = a.customer.name
                                b_value = b.customer.name

                                return a_value.localeCompare(b_value)

                            case 'status':

                                a_value = (a.integrations.statusCode == null ? '' : a.integrations.statusCode)
                                b_value = (b.integrations.statusCode == null ? '' : b.integrations.statusCode)

                                return a_value.localeCompare(b_value)
                            
                            case 'ref':

                                    a_value = (!!a.sender.ref ? a.sender.ref : '')
                                    b_value = (!!b.sender.ref ? b.sender.ref : '')
    
                                    return a_value.localeCompare(b_value)

                            case 'bus':

                                a_value = (!!a.sender.bus ? a.sender.bus : '')
                                b_value = (!!b.sender.bus ? b.sender.bus : '')

                                return a_value.localeCompare(b_value)

                            default:

                                a_value = a[sort]
                                b_value = b[sort]

                                return a_value.localeCompare(b_value)

                        }

                        // Use localeCompare for strings
                        
                    }
                })

                // Change direction to direction in defaults array or default to `DESC`
                let direction = this.sortDirectionDefaults.find((element) => {
                    return element.name === sort
                })

                // Set direction
                if(direction && direction.order !== 'DESC') {
                    this.sortingDirection = 'ASC'
                }
                else {
                    this.sortingDirection = 'DESC'
                    this.sortedOrders.reverse()
                }
            }
        }
    }


    /**
     * Changes sort direction to either `ASC` or `DESC` and reverses `sortedOrders`
     */
    changeSortDirection() {
        this.sortingDirection = this.sortingDirection === 'DESC' ? 'ASC' : 'DESC'
        this.sortedOrders.reverse()
    }


    /**
     * Moves month to first position, to be able to use `Date()`
     * 
     * @param date 
     */
    changeDateToLocaleString(date): number {

        const dateElement = date.split('.')
        const yearObject =  dateElement[2].split(' ')
        const year = yearObject[0]
        const timeStamp = yearObject[1].replace(':', '')

        return +`${year}${dateElement[1]}${dateElement[0]}${timeStamp}`
    }


    exludedFromCSV = ['prices.misc_delivery', 'integrations.closecopy', 'integrations.is_new_bus']
    /**
     * Downloads the current search result as CSV
     */
    download() {

        
        let titles = this.orders[0]
        let titleArray = []
        let flattenedOrders = []
        // Map out all titles for the CSV header
        for(let title of Object.keys(titles)) {

            // Primary titles
            if(!isObject(titles[title])) {
                if(!this.exludedFromCSV.includes(title)) {
                    titleArray.push(title)
                }

            } 
            // Secondary titles
            else {

                for(let subTitle of Object.keys(titles[title])) {
                    if(!this.exludedFromCSV.includes(title+'.'+subTitle)) {
                        titleArray.push(title+'.'+subTitle)
                    }
                }
            }
        }


        // Flatten products to match the CSV layout
        for(let order of this.orders) {

            let flattenedOrder = {}

            for(let value of Object.keys(order)) {


                // Secondary titles
                if(isObject(order[value])) {

                    for(let subValue of Object.keys(order[value])) {

                        if(titleArray.includes(value+'.'+subValue)) {
                            
                            // Special misc_delivery rule
                            if(value+'.'+subValue === 'prices.delivery' && order.prices.misc_delivery > 0) {
                                flattenedOrder[value+'.'+subValue] = order[value][subValue] + order.prices.misc_delivery
                            }
                            else {
                                flattenedOrder[value+'.'+subValue] = order[value][subValue]
                            }
                        }
                    }

                }
                // Primary titles
                else {
                    if(titleArray.includes(value))
                        flattenedOrder[value] = order[value]
                }
            }

            flattenedOrders.push(flattenedOrder)
        }

        // Creates a pseudo unique filename, by adding date, so it is possible to keep track of which files have been downloaded when
        let filename = `Kurve og ordre - ${new Date().toLocaleDateString()}`

        let options = {
            headers: titleArray,
            fieldSeparator: ';',
            quoteStrings: '"',
            decimalseparator: ',',
            showLabels: true, 
            showTitle: false,
            useBom: false
        }

        // console.log(flattenedOrders)
        new Angular2Csv(flattenedOrders, filename, options)
    }


    windowOpen(url) {
        let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=960px,height=800px,left=-400,top=-600`
        window.open(url, '', params)
    }


    /**
     * Removes basket from list
     * 
     * @param id 
     */
    removeOrder(id) {
        if(confirm(this._translate.transform('delete order?', 'search-orders'))) {

        this._searchOrders.removeOrder(id).then(() => {

            let element = this.orders

            for(let order of Object.keys(element)) {
                if(element[order].id == id) {
                    element[order].is_inactive = true
                    element[order].status = false
                }
            }
            this._searchOrders.setOrderList(element)
        })
        }
    }


    removeFromExpanded(id) {
        delete this.expandedIds[this.expandedIds.indexOf(id)]
    }

    addOrRemoveFromArray(id) {

        if(this.tabletExtendedIds.includes(id)) {
            delete this.tabletExtendedIds[this.tabletExtendedIds.indexOf(id)]
        } else {
            this.tabletExtendedIds.push(id)
        }
    }

    openDialog(quote_id: string) {
        this._dialog.open(StatusComponent, {
            height: '80%',
            width: '80%',
            maxWidth: '1024px',
            maxHeight: '1024px',
            panelClass: '',
            data: {
                quote_id: quote_id
            }
        })
    }
}