import streetData from '../data/streetCoordinates.json';

class StreetCoordinates {
  constructor() {
    this.data = streetData;
  }

  /**
   * Konvertiert relative Koordinaten (0-1) zu absoluten Koordinaten
   * @param {number} relativeX - Relative X-Koordinate (0-1)
   * @param {number} relativeY - Relative Y-Koordinate (0-1)
   * @param {number} tileSize - Größe des Tiles in Pixeln
   * @returns {Object} Absolute Koordinaten {x, y}
   */
  toAbsolute(relativeX, relativeY, tileSize) {
    return {
      x: Math.round(relativeX * tileSize),
      y: Math.round(relativeY * tileSize)
    };
  }

  /**
   * Konvertiert absolute Koordinaten zu relativen Koordinaten (0-1)
   * @param {number} absoluteX - Absolute X-Koordinate
   * @param {number} absoluteY - Absolute Y-Koordinate
   * @param {number} tileSize - Größe des Tiles in Pixeln
   * @returns {Object} Relative Koordinaten {x, y}
   */
  toRelative(absoluteX, absoluteY, tileSize) {
    return {
      x: absoluteX / tileSize,
      y: absoluteY / tileSize
    };
  }

  /**
   * Gibt die Straßenregionen für einen Tile-Typ zurück
   * @param {string} tileType - Typ des Tiles (z.B. 'cornerBottomRight')
   * @returns {Array} Array von Polygonen mit relativen Koordinaten (0-1)
   */
  getDriveableRegions(tileType) {
    const tile = this.data.tiles[tileType];
    if (!tile) {
      console.warn(`Tile type '${tileType}' not found`);
      return [];
    }

    // Gib die relativen Koordinaten (0-1) direkt zurück
    return tile.regions;
  }

  /**
   * Prüft, ob ein Punkt innerhalb der fahrbaren Bereiche liegt
   * @param {number} x - X-Koordinate des Punktes (relativ 0-1)
   * @param {number} y - Y-Koordinate des Punktes (relativ 0-1)
   * @param {string} tileType - Typ des Tiles
   * @returns {boolean} True wenn der Punkt fahrbar ist
   */
  isPointDriveable(x, y, tileType) {
    const regions = this.getDriveableRegions(tileType);
    
    for (const region of regions) {
      if (this.isPointInPolygon(x, y, region)) {
        return true;
      }
    }
    
    return false;
  }

  /**
   * Prüft, ob ein Punkt innerhalb eines Polygons liegt (Ray Casting Algorithm)
   * @param {number} x - X-Koordinate des Punktes
   * @param {number} y - Y-Koordinate des Punktes
   * @param {Array} polygon - Array von {x, y} Punkten
   * @returns {boolean} True wenn der Punkt im Polygon liegt
   */
  isPointInPolygon(x, y, polygon) {
    let inside = false;
    for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
      if (((polygon[i].y > y) !== (polygon[j].y > y)) &&
          (x < (polygon[j].x - polygon[i].x) * (y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x)) {
        inside = !inside;
      }
    }
    return inside;
  }

  /**
   * Zeichnet die Straßenregionen auf einem Canvas
   * @param {CanvasRenderingContext2D} ctx - Canvas 2D Context
   * @param {string} tileType - Typ des Tiles
   * @param {number} tileSize - Größe des Tiles in Pixeln
   * @param {number} offsetX - X-Offset für das Tile
   * @param {number} offsetY - Y-Offset für das Tile
   */
  drawDriveableRegions(ctx, tileType, tileSize, offsetX = 0, offsetY = 0) {
    const regions = this.getDriveableRegions(tileType);
    
    ctx.fillStyle = '#f0f0f0'; // Straßenfarbe
    ctx.strokeStyle = '#333';
    ctx.lineWidth = 1;
    
    for (const region of regions) {
      ctx.beginPath();
      // Konvertiere relative Koordinaten zu absoluten für das Zeichnen
      const startX = region[0].x * tileSize + offsetX;
      const startY = region[0].y * tileSize + offsetY;
      ctx.moveTo(startX, startY);
      
      for (let i = 1; i < region.length; i++) {
        const x = region[i].x * tileSize + offsetX;
        const y = region[i].y * tileSize + offsetY;
        ctx.lineTo(x, y);
      }
      
      ctx.closePath();
      ctx.fill();
      ctx.stroke();
    }
  }

  /**
   * Gibt alle verfügbaren Tile-Typen zurück
   * @returns {Array} Array von Tile-Typen
   */
  getAvailableTileTypes() {
    return Object.keys(this.data.tiles);
  }

  /**
   * Gibt die ursprüngliche Tile-Größe zurück
   * @returns {number} Ursprüngliche Tile-Größe in Pixeln
   */
  getOriginalTileSize() {
    return this.data.tileSize;
  }
}

// Singleton-Instanz
const streetCoordinates = new StreetCoordinates();

export default streetCoordinates;
