import { Component, OnInit } from '@angular/core';
import { Circle, CRS, ImageOverlay, LatLng, LatLngBounds, Rectangle } from "leaflet";
import { Server } from "../../../server";
import { IslandInstanceModel } from "../../../models/atlasData/island-instance.model";
import * as L from 'leaflet';
import 'leaflet-imageoverlay-rotated';

const RADIAN_RATIO = Math.PI / 180;

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

  options = {
    crs: CRS.Simple,
    zoom: -16,
    maxBounds: undefined,
    maxBoundsViscosity: 0.5,
    center: undefined,
    layers: [],
    minZoom: -16,
  };

  serverLayers = [];
  islandLayers = [];
  discoveryLayers = [];

  maxX: number;
  maxY: number;

  constructor(private server: Server) {
  }

  ngOnInit() {
    // all in Y X format. Also, upside down! (0,0 is bottom left instead of top left)
    // Also, due to insanely large sizes, divide by 100_000
    this.maxX = this.server.serverGrid.gridSize * this.server.serverGrid.totalGridsX;
    this.maxY = this.server.serverGrid.gridSize * this.server.serverGrid.totalGridsY;
    const northEast = new LatLng(0, this.maxX);
    const southWest = new LatLng(this.maxY, 0);
    this.options.maxBounds = new LatLngBounds(southWest, northEast);
    this.options.center = new LatLng(0, 0);
    this.options.layers.push(new ImageOverlay('./assets/server-grid-editor/WaterTiles/instinctworld-autoscaling.png', this.options.maxBounds));

    this.server.serverGrid.servers.forEach(s => {
      // Server Layer
      const servMinX = this.server.serverGrid.gridSize * s.gridX;
      const servMaxX = servMinX + this.server.serverGrid.gridSize;
      const servMinY = this.server.serverGrid.gridSize * s.gridY;
      const servMaxY = servMinY + this.server.serverGrid.gridSize;
      const servNE = new LatLng(servMinY, servMaxX);
      const servSW = new LatLng(servMaxY, servMinX);
      const servBounds = new LatLngBounds(servSW, servNE);
      this.serverLayers.push(new Rectangle(servBounds,{color: 'black', weight: 1}));

      s.islandInstances.forEach(i => {
        const imgUrl = this.server.islands.islandData[i.name].imagePath;
        const islandLocation = this.islandToImageRotation(i);
        this.islandLayers.push(L.imageOverlay.rotated(imgUrl, islandLocation[0], islandLocation[1], islandLocation[2]));
      });

      s.discoZones.forEach(d => {
        if (d.ManualVolumeName !== undefined) return;
        const imgUrl = './assets/server-grid-editor/Resources/discoZoneBox.png';
        const discoLocation = this.discoveryZoneToImageRotation(d);
        this.discoveryLayers.push(L.imageOverlay.rotated(imgUrl, discoLocation[0], discoLocation[1], discoLocation[2]));
      });
    })
  }

  gridCoordinateToMapLatLng(gridX: number, gridY: number): LatLng {
    // Need to invert gridY for the Latitude.
    const newY = this.maxY - gridY;
    return new LatLng(newY, gridX);
  }

  islandToImageRotation(island: IslandInstanceModel): LatLng[] {
    return this.gridCoordinateToImageRotation(island.worldX, island.worldY, island.rotation, island.islandWidth, island.islandHeight);
  }

  discoveryZoneToImageRotation(disco): LatLng[] {
    return this.gridCoordinateToImageRotation(disco.worldX, disco.worldY, disco.rotation, disco.sizeX, disco.sizeY);
  }

  gridCoordinateToImageRotation(worldX, worldY, rotation, width, height): LatLng[] {
    const halfWidth = width / 2;
    const halfHeight = height / 2;

    const radians = (rotation + 90) * RADIAN_RATIO;

    const cosR = Math.cos(radians);
    const sinR = Math.sin(radians);

    // https://gamedev.stackexchange.com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle
    // Rotate any point around
    // Nx = x * cos(a) - y * sin(a)
    // Ny = x * sin(a) + y * cos(a)

    // REMEMBER everything is upside down
    // Top Left -1, 1
    const topLeftX = worldX + (-halfWidth * cosR) - (halfHeight * sinR);
    const topLeftY = worldY + (-halfWidth * sinR) + (halfHeight * cosR);
    // Bottom Left -1, -1 BUT mirrored for some reason so 1, 1
    const botLeftX = worldX + (halfWidth * cosR) - (halfHeight * sinR);
    const botLeftY = worldY + (halfWidth * sinR) + (halfHeight * cosR);
    // Top Right 1, 1 BUT mirrored for some reason so -1, -1
    const topRightX = worldX + (-halfWidth * cosR) - (-halfHeight * sinR);
    const topRightY = worldY + (-halfWidth * sinR) + (-halfHeight * cosR);

    return [
        this.gridCoordinateToMapLatLng(topLeftX, topLeftY),
        this.gridCoordinateToMapLatLng(topRightX, topRightY),
        this.gridCoordinateToMapLatLng(botLeftX, botLeftY)
    ];
  }
}
