import { MatSnackBar } from '@angular/material/snack-bar';
import { DialogService } from 'src/app/core/dialog.service';
import { RoleUtil } from './../../core/role.util';
import { MapService } from './../map.service';
import { MapFeatureState, MapState } from './../store/map.reducers';
import { Store } from '@ngrx/store';
import { MapAttack, getMapAttackDescription } from './../model/MapAttack.model';
import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs';
import * as mapbox from 'mapbox-gl';
import { User } from 'src/app/core/model/user.model';
import { AuthState } from 'src/app/auth/store/auth.reducers';
import { MapSettings } from '../model/MapSettings.model';
import { Router } from '@angular/router';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss', './mapbox-gl.css'],
  encapsulation: ViewEncapsulation.None, 
})
export class MapComponent implements OnInit, OnDestroy {

  paintedAttacksCount: number;
  attacks: MapAttack[];
  settings: MapSettings;
  token: string;

  user: User;
  map: any;

  errorPage: boolean = false;

  mapStoreSubscription: Subscription;
  userStoreSubscription: Subscription;

  constructor(private store: Store<MapFeatureState>, private mapService: MapService, public roleUtil: RoleUtil, private dialogService: DialogService, private router: Router, private snackBar: MatSnackBar) {
    this.mapStoreSubscription = this.store.select('map').subscribe(
      (state: MapState) => {
        if (state.attacks !== null || state.settings !== null){ 
          this.attacks = state.attacks;
          this.settings = state.settings;
        }
        else
          this.mapService.requestMapAttacks();

        if (state.token !== null){
          this.token = state.token;
          mapbox.accessToken = state.token;
        }
        else
          this.mapService.requestMapToken();

        if (this.attacks && this.settings && this.token && !this.map){
          setTimeout(() => {
            this.map = new mapbox.Map({
              container: 'map-container',
              style: 'assets/mapbox/style.json',
              center: [this.settings.centerLongitude, this.settings.centerLatitude],
              zoom: this.settings.zoom
            });
            this.map.on('load', (event: any) => {
              this.drawMapAttackPoints(event.target, this.attacks);
              let source: any = this.map.getSource('attacks');
              if (source)
                this.paintedAttacksCount = source._data.features.length;
            });
            this.map.on('error', (event: any) => {
              if (event.error.status === 401)
                this.mapService.requestMapToken();
              else{
                this.snackBar.open('V mapách se vyskytla nočekávaná chyba. :(', 'zavřít', { duration: 2500 });
                this.router.navigate(['/']);
              }
            });
          }, 0);          
        }
      }
    );
    this.userStoreSubscription = this.store.select('authState').subscribe(
      (state: AuthState) => {
        this.user = state.user;
      }
    );
  }

  ngOnInit() {
  }

  ngOnDestroy() {
    this.mapStoreSubscription.unsubscribe();
    this.userStoreSubscription.unsubscribe();
    if (this.map)
      this.map.remove();
  }

  onSaveClick(){
    let latitude: number = Math.round(this.map.getCenter().lat*1000000)/1000000;
    let longitude: number = Math.round(this.map.getCenter().lng*1000000)/1000000;
    let zoom: number = Math.round(this.map.getZoom()*100)/100;
    let currentSettings: MapSettings = new MapSettings(this.settings.id, latitude, longitude, zoom);
    this.dialogService.confirm(
      'Uložit zobrazení ?', 
      'Přejete si nastavit vaše aktuální zobrazení (zeměpisná délka: '+currentSettings.centerLongitude+', zeměpisná šířka: '+currentSettings.centerLatitude+', zoom: '+currentSettings.zoom+') jako výchozí zobrazení mapy pro všechny uživatele?', 
      400
    ).subscribe(
      (result: boolean) => {
        if (result){
          this.mapService.updateMapSettings(currentSettings);
        }
      }
    );
  }

  private drawMapAttackPoints(map: any, attacks: MapAttack[]){
    let features: any[] = attacks.filter((attack: MapAttack) => attack.latitude && attack.longitude).map((attack: MapAttack) => {
      return {
        "type": "Feature",
        "properties": {
            "description": getMapAttackDescription(attack),
            "id": attack.id
        },
        "geometry": {
            "type": "Point",
            "coordinates": [attack.longitude, attack.latitude]
        }
      }
    });

    map.addSource('attacks', {
      "type": "geojson",
      "data": {
          "type": "FeatureCollection",
          "features": features
      }
    });

    map.addLayer({
      "id": "attacks",
      "type": "circle",
      'paint': {
        'circle-radius': {
          'base': 5,
          'stops': [[2, 4], [4, 8], [6, 12], [8, 16], [10, 20]]
        },
        'circle-color': '#d84a5c'
      },
      "source": 'attacks'
    });

    map.on('click', 'attacks', (e) => {
      let id = e.features[0].properties.id;
      if (this.roleUtil.hasAnalystRights(this.user))
        this.router.navigate(['/database/'+id]);
    });

    var popup = new mapbox.Popup({
      closeButton: false,
      closeOnClick: false
    });
    
    map.on('mouseenter', 'attacks', (e) => { 
      var coordinates = e.features[0].geometry.coordinates.slice();
      var description = e.features[0].properties.description;
      while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
          coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
      }
      popup.setLngLat(coordinates).setHTML(description).addTo(map);
    });
    
    map.on('mouseleave', 'attacks', () => {
      popup.remove();
    });
  }
}
