// Imports
import * as PartyModel from "/services/model/party-model.js";
import * as AreaModel from "/services/model/area-model.js";
import * as ElectionModel from "/services/model/election-model.js";

export async function mount(parent) {
  const mapComponent = new MapComponent(parent);
  return mapComponent;
}

class MapComponent {
  constructor(parent) {
    this.parent = parent;
    this.PartyModel = PartyModel.getPartyModel();
    this.AreaModel = AreaModel.getAreaModel();
    this.ElectionModel = ElectionModel.getElectionModel();
  }

  async displayMapAreas() {
    let election = await this.ElectionModel.getElection(
      this.parent.parent.round.ElectionID
    );
    await this.initMap(
      election.MapAreaFile.replace("web/", ""),
      this.colorAreas
    );
  }

  async displayMapSections() {
    let election = await this.ElectionModel.getElection(
      this.parent.parent.round.ElectionID
    );
    await this.initMap(election.MapSectionFile.replace("web/", ""), this.colorSections);
  }

  async initMap(mapFile, colorationFunction) {
    // Create datasource
    const request = new XMLHttpRequest();
    request.open("GET", mapFile, false);
    request.send(null);
    this.dataSource = JSON.parse(request.responseText);

    // Add parties and colors to datasource
    this.dataSource = await colorationFunction(this, this.dataSource);

    document.getElementById("map-component").innerHTML = "";
    // Create a popup, but don't add it to the map yet.
    let popup = new mapboxgl.Popup({
      closeButton: false,
    });

    this.map = new mapboxgl.Map({
      container: "map-component", // container id
      style: "/assets/mapbox/vector.json", // stylesheet location
      center: [4.9, 45.75], // starting position [lng, lat]
      zoom: 9.5, // starting zoom
    });

    this.map.on("load", () => {
      this.map.addSource("data-source", {
        type: "geojson",
        data: this.dataSource,
      });

      this.map.addLayer(
        {
          id: "winners-fills",
          type: "fill",
          source: "data-source",
          layout: {},
          paint: {
            "fill-color": { type: "identity", property: "color" },
            "fill-opacity": 0.5,
            "fill-outline-color": "black",
          },
        },
        "place_label_city"
      );

      this.map.addLayer({
        id: "winners-names",
        type: "symbol",
        source: "data-source",
        filter: ["all"],
        layout: {
          "text-field": "{partyName}",
          "text-font": ["titiliumweb-regular"],
        },
      });
    });

    this.map.on("mousemove", "winners-fills", (e) => {
      // Change the cursor style as a UI indicator.
      this.map.getCanvas().style.cursor = "pointer";

      // Single out the first found feature.
      const feature = e.features[0];

      if (e.features.length > 0) {
        // Display a popup with the name of the county
        popup
          .setLngLat(e.lngLat)
          .setText(
            `${feature.properties.Name} : ${
              feature.properties.partyName == undefined
                ? "aucun"
                : feature.properties.partyName
            }`
          )
          .addTo(this.map);
      }
    });

    this.map.on("mouseleave", "winners-fills", () => {
      this.map.getCanvas().style.cursor = "";
      popup.remove();
    });
  }

  async colorAreas(mapHandler, dataSource) {
    for (let area of mapHandler.parent.parent.results.areasResults) {
      if (area.status == mapHandler.parent.parent.filter) {
        let party = await mapHandler.PartyModel.getParty(
          area.candidateLists[0].PartyID
        );
        dataSource = mapHandler.colorTiles(
          dataSource,
          parseInt(area.MapID),
          party.Name,
          party.Color
        );
      } else {
        dataSource = mapHandler.colorTiles(dataSource, area.MapID, "", "");
      }
    }
    return dataSource;
  }

  async colorSections(mapHandler, dataSource) {
    mapHandler.parent.parent.results.areasResults.forEach(async (area) => {
      for (let section of area.Sections) {
        if (section.status == mapHandler.parent.parent.filter) {
          let party = await mapHandler.PartyModel.getParty(
            section.candidateLists[0].PartyID
          );
          dataSource = mapHandler.colorTiles(
            dataSource,
            parseInt(section.MapID),
            party.Name,
            party.Color
          );
        } else {
          dataSource = mapHandler.colorTiles(dataSource, section.MapID, "", "");
        }
      }
    });
    return dataSource;
  }

  colorTiles(dataSource, gid, partyName, color) {
    for (let f of dataSource.features) {
      if (f.properties.nomcircons) f.properties.Name = f.properties.nomcircons;
      if (f.properties["Nom réduit"])
        f.properties.Name = f.properties["Nom réduit"];
      if (f.properties.gid === gid) {
        f.properties.partyName = partyName;
        f.properties.color = color;

        break;
      }
    }
    return dataSource;
  }
}