import { NgFor } from '@angular/common';
import {
  Component,
  EventEmitter,
  OnInit,
  Output,
  ViewContainerRef,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import * as L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { Pin } from '../../model/Pin';
import { AutocompleteService } from '../../services/auto-complete/auto-complete.service';
import { MapReloadService } from '../../services/map-reload/map-reload.service';
import { PinService } from '../../services/pin/pin.service';
import { PinMarkerComponent } from '../pin-marker/pin-marker.component';
import { ModalService } from '../../services/modal/modal.service';

@Component({
  selector: 'app-leaflet-map',
  templateUrl: './leaflet-map.component.html',
  standalone: true,
  imports: [NgFor, FormsModule],
})
export class LeafletMapComponent implements OnInit {
  private map!: L.Map;
  private markersMap: { [key: string]: L.Marker } = {};
  private allPins: Pin[] = [];
  private pinCountries: { [pinId: string]: string } = {};

  availableCountries: string[] = [];
  availablePersons: string[] = [];
  selectedCountry: string = '';
  selectedPerson: string = '__all__';

  fileNames: string[] = [];
  @Output() filesSelected = new EventEmitter<FileList>();

  constructor(
    private viewContainerRef: ViewContainerRef,
    private pinsService: PinService,
    private autocompleteService: AutocompleteService,
    private route: ActivatedRoute,
    private router: Router,
    private modalService: ModalService,
    private mapReloadService: MapReloadService
  ) {}

  ngOnInit(): void {
    this.initializeMap();

    this.mapReloadService.reload$.subscribe(() => {
      this.loadPins(); // recharge les pins quand demandé
    });

    this.route.queryParams.subscribe((params) => {
      const pinId = params['pin'];
      if (pinId) {
        const marker = this.markersMap[pinId];
        if (marker) {
          marker.openPopup();
          const latlng = marker.getLatLng();
          const zoom = this.map.getZoom();
          const offsetLat = 0.05 / Math.pow(2, zoom - 10);
          this.map.setView(L.latLng(latlng.lat + offsetLat, latlng.lng), zoom);
        }
      }
    });
  }

  private initializeMap(): void {
    this.map = L.map('map', {
      maxBounds: L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180)),
      maxBoundsViscosity: 1.0,
      minZoom: 2,
    }).setView([46.603354, 1.888334], 6);

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '',
    }).addTo(this.map);
    this.map.attributionControl.setPrefix('');

    this.pinsService.getPins().subscribe((pins: Pin[]) => {
      this.allPins = pins;
      this.extractPersons(pins);

      this.renderPins(); // Afficher d'abord les pins sans les filtres
      this.loadCountriesForFiltrers(pins); // Ensuite, charger les pays en arrière-plan
    });
  }

  private loadCountriesForFiltrers(pins: Pin[]): void {
    const countrySet = new Set<string>();
    const requests = pins.map((pin) =>
      this.autocompleteService
        .getAddressFromCoordinates(pin.location[0], pin.location[1])
        .toPromise()
        .then((res: any) => {
          const address = res?.address;
          const country =
            address?.country ||
            this.extractLastFromDisplayName(res?.display_name);
          if (country) {
            this.pinCountries[pin.id] = country;
            countrySet.add(country);
          }
        })
        .catch((err: any) => {
          console.error(
            'Erreur lors de la récupération du pays pour le pin',
            pin.id,
            err
          );
        })
    );

    Promise.all(requests).then(() => {
      this.availableCountries = Array.from(countrySet).sort();
    });
  }

  private extractLastFromDisplayName(displayName: string): string {
    if (!displayName) return '';
    const parts = displayName.split(',');
    return parts[parts.length - 1].trim();
  }

  private extractPersons(pins: Pin[]): void {
    const personsSet = new Set<string>();
    const regex = /@(\w+)/g;
    pins.forEach((pin) => {
      const desc = pin.description || '';
      let match;
      while ((match = regex.exec(desc)) !== null) {
        personsSet.add(match[1]);
      }
    });
    this.availablePersons = Array.from(personsSet).sort();
  }

  onCountryChange(country: string) {
    this.selectedCountry = country;
    this.renderPins();
  }

  onPersonChange(person: string) {
    this.selectedPerson = person;
    this.renderPins();
  }

  private renderPins(): void {
    // Remove existing markers
    Object.values(this.markersMap).forEach((marker) =>
      this.map.removeLayer(marker)
    );
    this.markersMap = {};

    const visitedIcon = this.createDivIcon(`
      <svg class="w-6 h-6 text-gray-800" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
        <path fill-rule="evenodd" d="M11.906 1.994a8.002 8.002 0 0 1 8.09 8.421 7.996 7.996 0 0 1-1.297 3.957.996.996 0 0 1-.133.204l-.108.129c-.178.243-.37.477-.573.699l-5.112 6.224a1 1 0 0 1-1.545 0L5.982 15.26l-.002-.002a18.146 18.146 0 0 1-.309-.38l-.133-.163a.999.999 0 0 1-.13-.202 7.995 7.995 0 0 1 6.498-12.518ZM15 9.997a3 3 0 1 1-5.999 0 3 3 0 0 1 5.999 0Z" clip-rule="evenodd"/>
      </svg>
    `);

    const filteredPins = this.allPins.filter((pin) => {
      const pinCountry = this.pinCountries[pin.id];
      const matchesCountry = this.selectedCountry
        ? pinCountry === this.selectedCountry
        : true;
      const matchesPerson =
        this.selectedPerson === '__all__'
          ? true
          : this.selectedPerson === '__none__'
          ? !pin.description?.match(/@\w+/)
          : pin.description?.includes(`@${this.selectedPerson}`);

      return matchesCountry && matchesPerson;
    });

    filteredPins.forEach((pin) => {
      const marker = L.marker(pin.location as [number, number], {
        icon: visitedIcon,
      }).addTo(this.map);

      marker.on('popupclose', () => {
        this.router.navigate(['/map']);
      });

      marker.on('popupopen', () => {
        this.router.navigate(['/map'], { queryParams: { pin: pin.id } });
      });

      const popupDiv = document.createElement('div');
      const componentRef =
        this.viewContainerRef.createComponent(PinMarkerComponent);
      componentRef.instance.pin = pin;
      componentRef.instance.marker = marker;
      popupDiv.appendChild(componentRef.location.nativeElement);

      marker.bindPopup(popupDiv, { closeButton: false, minWidth: 150 });

      this.markersMap[pin.id] = marker;

      this.route.queryParams
        .subscribe((params) => {
          const pinId = params['pin'];
          if (pinId) {
            const marker = this.markersMap[pinId];
            if (marker) {
              marker.openPopup();
              const latlng = marker.getLatLng();
              const zoom = this.map.getZoom();
              const offsetLat = 0.05 / Math.pow(2, zoom - 10);
              this.map.setView(
                L.latLng(latlng.lat + offsetLat, latlng.lng),
                zoom
              );
            }
          }
        })
        .unsubscribe();
    });
  }

  private createDivIcon(htmlContent: string): L.DivIcon {
    return L.divIcon({
      html: htmlContent,
      className: 'text-2xl text-blue-500',
      iconSize: [24, 24],
      iconAnchor: [12, 24],
      popupAnchor: [0, -24],
    });
  }

  public loadPins(): void {
    this.pinsService.getPins().subscribe((pins: Pin[]) => {
      this.allPins = pins;
      this.extractPersons(pins);
      this.renderPins(); // Afficher d'abord les pins sans les filtres

      this.loadCountriesForFiltrers(pins); // Ensuite, charger les pays en arrière-plan
    });
  }



  async onFilesSelected(event: Event): Promise<void> {
    const input = event.target as HTMLInputElement;
    if (input.files && input.files.length > 0) {
      this.fileNames = Array.from(input.files).map((f) => f.name);
      this.filesSelected.emit(input.files);
      this.modalService.openModal('add-pin-modal');
    }
  }

  onDragOver(event: DragEvent) {
    event.preventDefault();
  }

  onDrop(event: DragEvent) {
    event.preventDefault();
    if (event.dataTransfer && event.dataTransfer.files.length > 0) {
      this.filesSelected.emit(event.dataTransfer.files);
      const images: File[] = Array.from(event.dataTransfer.files);
      this.modalService.openModal('add-pin-modal', images);
    }

    console.log('Image dropped on map : ', event.dataTransfer?.files);
  }
}
