import { Component, signal, OnInit, ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LeafletModule } from '@bluehalo/ngx-leaflet';
import { center } from '@turf/turf';
import { Overpass } from '../overpass';
import * as L from 'leaflet';
import * as G from 'geojson';

import * as D from './details';

@Component({
  selector: 'app-map',
  imports: [LeafletModule, CommonModule],
  templateUrl: './map.html',
  styleUrl: './map.scss',
})
export class OSMMap implements OnInit {
  private buildingLayer?: L.LayerGroup;

  protected readonly title = signal('HKA-OSM');
  map?: L.Map;
  details?: D.Details;

  osm?: L.TileLayer;
  options: L.MapOptions = {};
  layerControl?: L.Control.Layers;

  isFullscreen = true;

  constructor(
    private overpass: Overpass,
    private cdr: ChangeDetectorRef,
  ) {}

  ngOnInit() {
    this.osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxNativeZoom: 19,
      maxZoom: 21,
      minZoom: 18,
      attribution: '© OpenStreetMap contributors',
    });

    // Define map options
    this.options = {
      layers: [this.osm],
      zoom: 18, // Zoom level
      center: this.getCenter(), // Center of the map
    };

    this.layerControl = L.control.layers({
      OpenStreetMap: this.osm,
    });
  }

  onMapReady(map: L.Map) {
    this.map = map;
    this.layerControl?.addTo(this.map);
    this.queryBuildingData().addTo(this.map);
    console.log('Map is ready');
  }

  queryBuildingData() {
    // Query the Overpass API for building data and add it to the map as a GeoJSON layer.

    const buildingLayer = new L.LayerGroup();

    this.overpass.fetchBuildingData().subscribe((data) => {
      console.log('Received building data:', data);
      L.geoJSON(this.createFeatureCollection(data), {
        style: { color: '#d62305', weight: 2, fillColor: '#d4caca', fillOpacity: 1 },
        onEachFeature: (feature, layer) => {
          layer.on({
            click: (e) => {
              this.isFullscreen = !this.isFullscreen;
              if (!this.isFullscreen) {
                this.map?.setView(this.getCenter(feature.geometry), 20);
                this.buildingLayer = this.queryIndoorData(feature.properties.name);
                this.buildingLayer.addTo(this.map!);
                this.details = new D.Details(feature.properties.name, feature.properties.building);
              } else {
                this.map?.setView(this.getCenter(), 18);
                if (this.buildingLayer) {
                  this.map?.removeLayer(this.buildingLayer);
                }
              }
              console.log('Set isFullscreen to:', this.isFullscreen);
              console.log('Clicked on feature:', feature.properties?.name);
              this.cdr.detectChanges();
            },
          });
          if (feature.properties && feature.properties.name) {
            layer.bindTooltip(feature.properties.name, {
              permanent: false,
              direction: 'top',
            });
          }
        },
      }).addTo(buildingLayer);
    });
    return buildingLayer;
  }

  queryIndoorData(building_name: string): L.LayerGroup {
    // Get the building name from the feature properties and query the Overpass API for detailed building data,
    // including indoor features.

    // Create a new LayerGroup to hold the building polygons
    const resultingLayer = new L.LayerGroup();

    this.overpass.fetchIndoorData(building_name).subscribe((data) => {
      console.log('Received indoor data for building:', building_name, data);
      L.geoJSON(this.createFeatureCollection(data), {
        style: { color: '#999999', fillColor: '#e0e0e0', fillOpacity: 1 },
        onEachFeature: (feature, layer) => {
          if (feature.properties) {
            layer.bindTooltip(feature.properties.ref ?? 'Test', {
              permanent: false,
              direction: 'top',
            });
          }
        },
      }).addTo(resultingLayer);
    });
    return resultingLayer;
  }

  private getCenter(feature?: any): L.LatLng {
    // Calculate the center of the feature using Turf.js, or use a default center if no feature is provided.
    let centerPoint: number[] = [];
    if (feature) {
      centerPoint = center(feature).geometry.coordinates.reverse();
    } else {
      centerPoint = [49.015514096207895, 8.391567600294243];
    }
    const result = new L.LatLng(centerPoint[0], centerPoint[1]);
    return result;
  }

  private createFeatureCollection(data: any): G.FeatureCollection {
    const buildingData: G.FeatureCollection = {
      type: 'FeatureCollection',
      features: [],
    };

    // Create a mapping of node IDs to their coordinates
    const nodes: Map<number, L.LatLng> = new Map();
    data.elements.forEach((element: any) => {
      if (element.type === 'node') {
        nodes.set(element.id, new L.LatLng(element.lat, element.lon));
      }
    });

    // Process ways and create polygons
    // TODO: Change to features, to also add the meta data of the building, e.g. the name of the room
    data.elements.forEach((element: any) => {
      if (element.type === 'way') {
        const coordinates: L.LatLng[] = [];
        element.nodes.forEach((nodeId: number) => {
          coordinates.push(nodes.get(nodeId)!);
        });
        buildingData.features.push(
          this.createFeature(new Map(Object.entries(element.tags || {})), coordinates),
          // this.createFeature(new Map(Object.entries({ name: 'Test' })), coordinates),
        );
      }
    });
    return buildingData;
  }

  private createFeature(properties: Map<string, string>, coordinates: L.LatLng[]): G.Feature {
    return {
      type: 'Feature',
      properties: Object.fromEntries(properties),
      geometry: {
        type: 'Polygon',
        coordinates: [coordinates.map((coord) => [coord.lng, coord.lat])],
      },
    };
  }
}
