import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'

import { FormControl } from '@angular/forms'
import { MatSnackBar } from '@angular/material/snack-bar'

import { ConfigService } from '../../_services/config.service'
import { MapControlService } from '../map-control.service'
import { TreeLayerItemComponent } from '../tree-layer-item/tree-layer-item.component'
import { InfoDataService, TaggedLayer } from '../../info/info-data.service'
import { MapDataService, BaseStyle } from '../map-data.service'
import { LayerNode } from '../models'
import { AuthenticationService } from '../../_services/authentication.service'
import { CreateBaseMapDialogComponent } from './create-base-map-dialog'
import { MatDialog } from '@angular/material/dialog'
import { BaseMapWithStores } from '../../openapi'

@Component({
    selector: 'gisaf-map-controls',
    templateUrl: './map-controls.component.html',
    styleUrls: ['./map-controls.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MapControlsComponent implements OnInit {
    baseUrl: string = '/gj/'
    simplify: number = 2
    simplify_max: number = 100
    simplify_step: number = 1

    searchText: string
    tagsFilterText: string

    baseStyles: BaseStyle[]

    baseStyleOpacity: number = this.configService.conf.value.bsData?.map.opacity

    status = new FormControl([])

    // canCreateBaseMap: boolean = false

    constructor(
        public snackBar: MatSnackBar,
        public configService: ConfigService,
        public mapControlService: MapControlService,
        protected infoDataService: InfoDataService,
        public mapDataService: MapDataService,
        public authenticationService: AuthenticationService,
        public dialog: MatDialog,
    ) {
    }


    ngOnInit() {
        this.mapControlService.layerLoaded$.subscribe({
            next: layerNode => {
                let item = layerNode.treeElement
                item.checked = true
                item.indeterminate = false
                item.cdr.markForCheck()
            },
            error: err => {
                /*
                item.checked = false
                item.indeterminate = false
                item.cdr.markForCheck()
                if (err.status == 401) {
                    this.openSnackBar('Not authorized')
                }
                else if (err.error) {
                    this.openSnackBar(err.error)
                }
                else {
                    this.openSnackBar("Unexpected problem: " + err.message)
                }
                */
                console.error(err)
            }
        })

        this.mapControlService.baseStyleOpacitySlider$.subscribe(
            value => {
                this.baseStyleOpacity = value
            }
        )

        this.mapControlService.search$.subscribe(
            forceReload => this.filter(forceReload)
        )

        /*
        for (let s in this.baseStyles) {
            if ('openmaptiles' in this.baseStyles[s]['sources']) {
                this.baseStyles[s]['sources']['openmaptiles']['url'] = 'https://free.tilehosting.com/data/v3.json?key=' + this.conf['map']['openMapTilesKey']
            }
            else if ('gisafTiles' in this.baseStyles[s]['sources']) {
                this.baseStyles[s]['sources']['gisafTiles']['url'] = this.conf['map']['tilesUrl']
                this.baseStyles[s]['sprite'] = this.conf['map']['spriteUrl']
            }
        }
         */

        this.status.valueChanges.subscribe(
            value => {
                this.mapControlService.status.next(value)
            }
        )
        this.status.setValue(this.configService.conf.value.bsData?.map['defaultStatus'])

        this.mapControlService.baseStyleOpacity.next(this.baseStyleOpacity)

        // this.canCreateBaseMap = this.authenticationService.isAuthorized(['base_map_creator'])
    }

    openSnackBar(msg: string):void {
        this.snackBar.open(msg, 'close', {duration: 3000})
    }

    showLayer(item: TreeLayerItemComponent): void {
        item.indeterminate = true
        this.mapControlService.addLayer(<LayerNode>item.node, this.simplify)
    }

    hideLayer(item: TreeLayerItemComponent) {
        this.mapControlService.removeLayer(item.node as LayerNode)
        item.indeterminate = false
        item.checked = false
    }

    toggleInfo(event) {
        this.mapControlService.toggleInfo(event.checked)
    }

    filter(forceReload: boolean = false) {
        if (this.tagsFilterText && this.mapControlService.hasTags.getValue()) {
            this.infoDataService.getTaggedLayers(
                this.mapControlService.selectedLayers,
                forceReload
            ).subscribe(
                (taggedLayers: TaggedLayer[]) => {
                    this.mapControlService.filter(this.searchText, taggedLayers, this.tagsFilterText)
                }
            )
        }
        else {
            this.mapControlService.filter(this.searchText)
        }
    }

    downloadSelectedLayers(format: String='gpkg', reproject: Boolean=false) {
        let selectedLayersStores = this.mapControlService.selectedLayers.map(
            (l: LayerNode) => l.store
        )
        if (selectedLayersStores.length == 0) {
            this.openSnackBar("There's no layer to download, please make a selection")
        }
        else {
            window.open('/download/layers/' + format + '/' + selectedLayersStores.join(',')
                        + '?reproject=' + reproject)
        }
    }

    createBaseMap() {
        let selectedLayersStores = this.mapControlService.selectedLayers.map(
            (l: LayerNode) => l.store
        )

        let instruction = selectedLayersStores.length == 0 ?
            "There's no layer selected, give a base map name to delete it." :
            "Give a name of a base map name to create or update it."

        const dialogRef = this.dialog.open(CreateBaseMapDialogComponent, {
            width: '25em',
            data: {
                instruction: instruction,
                stores: selectedLayersStores
            }
        })

        dialogRef.afterClosed().subscribe(
            result => result &&
                this.mapDataService.createBaseMap(
                    result.baseMapName,
                    result.stores
                ).subscribe(
                    (baseMap: BaseMapWithStores) => this.mapControlService.addBaseMap.next(baseMap)
                )
        )
    }
}