import {Component, OnInit, ViewChild} from '@angular/core';
import {AgmMap} from '@agm/core';
import {RestService} from '../../services/rest.service';
import {NGXLogger} from 'ngx-logger';
import {interval, Subscription} from 'rxjs';
import {startWith, switchMap} from 'rxjs/operators';
import {
  Car,
  CarEntity,
  CarEvent,
  GeoCoordinates, TrafficLight,
  TrafficLightEntity, TrafficLightEvent
} from '../../interfaces/interface';

@Component({
  selector: 'app-landing',
  templateUrl: './landing.component.html',
  styleUrls: ['./landing.component.css']
})
export class LandingComponent implements OnInit {

  constructor(
    private restService: RestService,
    private logger: NGXLogger
  ) {
  }

  @ViewChild('map') map: AgmMap;


  zoom = 14;
  center = {lat: 47.90620, lng: 16.20785};

  traffic_light_markers = new Map();
  car_markers = new Map();
  infoWindows = new Map();

  timeInterval: Subscription;

  TL_RED_IMAGE = 'assets/pictures/traffic_light_red.png';
  TL_GREEN_IMAGE = 'assets/pictures/traffic_light_green.png';
  CAR_IMAGE = 'assets/pictures/car.png';
  CAR_IMAGE_NCE = 'assets/pictures/car_orange.png';
  NCE_SOUND = 'assets/sound/crash.mp3';

  ngOnInit() {
    this.getTrafficLights();
    this.getCars();
  }


  getCarEvents(vin) {
    this.timeInterval = interval(1000)
      .pipe(
        startWith(0),
        switchMap(() => this.restService.getCarEvents(vin))
      ).subscribe((data: any) => {
          if (data.body === '') {
            return;
          }
          const carEvent = data.body as CarEvent;
          const car = this.car_markers.get(vin) as Car;
          car.carEvent = carEvent;
          this.car_markers.set(car['vin'], car);

        },
        err => this.logger.error(err),
        () => {
          this.logger.debug('loaded car events');
        }
      );
  }

  getTrafficLightEvents(tlid) {

    this.timeInterval = interval(1000)
      .pipe(
        startWith(0),
        switchMap(() => this.restService.getTrafficLightEvents(tlid))
      ).subscribe(
        (data: any) => {
          const trafficLightEvent = data.body as TrafficLightEvent;
          const trafficLight = this.traffic_light_markers.get(tlid) as TrafficLight;
          trafficLight.trafficLightEvent = trafficLightEvent;
          this.traffic_light_markers.set(tlid, trafficLight);
        },
        err => this.logger.error(err),
        () => {
          this.logger.debug('loaded traffic light events');
        }
      );
  }

  getTrafficLights() {
    this.restService.getTrafficLights().subscribe(
      (data: TrafficLightEntity[]) => {
        for (const trafficLightEntity of data) {

          const trafficLight: TrafficLight = {
            trafficLightEntity: trafficLightEntity,
            trafficLightEvent: this.getEmptyTrafficLightEvent()
          };
          this.traffic_light_markers.set(trafficLightEntity['id'], trafficLight);
        }
      },
      err => this.logger.error(err),
      () => {
        this.logger.debug('loaded traffic lights');
        for (const value of this.traffic_light_markers.values()) {
          this.getTrafficLightEvents(value.trafficLightEntity['id']);
        }
      }
    );
  }

  getCars() {
    this.restService.getCars().subscribe(
      (data: CarEntity[]) => {
        for (const carEntity of data) {
          const car: Car = {
            carEntity: carEntity,
            carEvent: this.getEmptyCarEvent()
          };
          this.car_markers.set(carEntity['vin'], car);
        }
      },
      err => this.logger.error(err),
      () => {
        this.logger.debug('loaded cars');
        for (const value of this.car_markers.values()) {
          this.getCarEvents(value.carEntity['vin']);
        }
      }
    );

  }

  trafficLightToImage(trafficLight) {
    return (trafficLight === 'RED') ? this.TL_RED_IMAGE : this.TL_GREEN_IMAGE;
  }

  getIconUrlCar(near_crash_event) {
    if (near_crash_event === true) {
      this.playCrashSound();
      return this.CAR_IMAGE_NCE;
    } else {
      return this.CAR_IMAGE;
    }
  }

  openInfoWindow(id) {
    this.infoWindows.set(id, true);
  }

  closeInfoWindow(id) {
    this.infoWindows.delete(id);
  }

  isInfoWindowOpen(id) {
    return this.infoWindows.has(id);
  }

  playCrashSound() {
    const audio = new Audio();
    audio.src = this.NCE_SOUND;
    audio.load();
    audio.play();
  }

  private getEmptyGeoCoordinates(): GeoCoordinates {
    return {
      latitude: 0,
      longitude: 0
    };
  }

  private getEmptyCarEvent(): CarEvent {
    return {
      near_crash_event: false,
      gps_location: this.getEmptyGeoCoordinates(),
      timestamp: '',
      velocity: 0
    };
  }

  private getEmptyTrafficLightEvent(): TrafficLightEvent {
      return {
        last_switch: 0,
        color: '',
        tlid: 0
      };
  }
}
