'use strict';

/**
 * Sistema modular de coordenadas do mapa mundial.
 * Define limites, dimensões, conversões, posições iniciais e migração da antiga grelha.
 */
(() => {
  const VERSION = 3;
  // Orientação visual do mapa mundial. Mantém as coordenadas guardadas, mas apresenta
  // o mundo rodado 180 graus para corrigir o sentido visual do mapa.
  const MAP_ROTATION_DEGREES = 180;
  const WORLD_WIDTH = 12000;
  const WORLD_HEIGHT = 8000;
  const COORD_MIN = -1000;
  const COORD_MAX = 1000;
  const COORD_CENTER = 0;
  const COORD_SPAN = COORD_MAX - COORD_MIN;
  const LEGACY_MIN = 0;
  const LEGACY_MAX = 999;

  const FALKEN_POSITIONS = Object.freeze([
    Object.freeze({ x: -640, y: -499 }),
    Object.freeze({ x: -299, y: 241 }),
    Object.freeze({ x: 161, y: -600 }),
    Object.freeze({ x: 542, y: -39 }),
    Object.freeze({ x: -499, y: 642 }),
    Object.freeze({ x: -39, y: 502 }),
    Object.freeze({ x: 441, y: 682 }),
    Object.freeze({ x: 762, y: -660 })
  ]);

  const clamp = (value, min, max) => Math.max(min, Math.min(max, value));

  function normalizeCoordinate(value, fallback = COORD_CENTER) {
    const parsed = Number(value);
    return clamp(Math.round(Number.isFinite(parsed) ? parsed : fallback), COORD_MIN, COORD_MAX);
  }

  function coordinateToRawPixelX(coordinate) {
    return Math.round((normalizeCoordinate(coordinate) - COORD_MIN) / COORD_SPAN * WORLD_WIDTH);
  }

  function coordinateToRawPixelY(coordinate) {
    return Math.round((normalizeCoordinate(coordinate) - COORD_MIN) / COORD_SPAN * WORLD_HEIGHT);
  }

  function coordinateToPixelX(coordinate) {
    return MAP_ROTATION_DEGREES === 180
      ? WORLD_WIDTH - coordinateToRawPixelX(coordinate)
      : coordinateToRawPixelX(coordinate);
  }

  function coordinateToPixelY(coordinate) {
    return MAP_ROTATION_DEGREES === 180
      ? WORLD_HEIGHT - coordinateToRawPixelY(coordinate)
      : coordinateToRawPixelY(coordinate);
  }

  function pixelToCoordinateX(pixel) {
    const safePixel = clamp(Number(pixel) || 0, 0, WORLD_WIDTH);
    const orientedPixel = MAP_ROTATION_DEGREES === 180 ? WORLD_WIDTH - safePixel : safePixel;
    return normalizeCoordinate(COORD_MIN + orientedPixel / WORLD_WIDTH * COORD_SPAN);
  }

  function pixelToCoordinateY(pixel) {
    const safePixel = clamp(Number(pixel) || 0, 0, WORLD_HEIGHT);
    const orientedPixel = MAP_ROTATION_DEGREES === 180 ? WORLD_HEIGHT - safePixel : safePixel;
    return normalizeCoordinate(COORD_MIN + orientedPixel / WORLD_HEIGHT * COORD_SPAN);
  }

  function migrateLegacyCoordinate(value, fallback = COORD_CENTER) {
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) return normalizeCoordinate(fallback);
    const legacy = clamp(parsed, LEGACY_MIN, LEGACY_MAX);
    return normalizeCoordinate(COORD_MIN + (legacy - LEGACY_MIN) / (LEGACY_MAX - LEGACY_MIN) * COORD_SPAN, fallback);
  }

  function stringHash(text) {
    let hash = 2166136261;
    for (const char of String(text || 'reino')) {
      hash ^= char.charCodeAt(0);
      hash = Math.imul(hash, 16777619);
    }
    return hash >>> 0;
  }

  function positionForSeed(seed) {
    const first = stringHash(seed);
    const second = stringHash(`${seed}:y:${first}`);
    const margin = 120;
    const usableSpan = COORD_SPAN - margin * 2;
    return {
      x: COORD_MIN + margin + (first % (usableSpan + 1)),
      y: COORD_MIN + margin + (second % (usableSpan + 1))
    };
  }

  function isInBounds(x, y) {
    return Number(x) >= COORD_MIN && Number(x) <= COORD_MAX && Number(y) >= COORD_MIN && Number(y) <= COORD_MAX;
  }

  globalThis.ReinosWorldCoordinates = Object.freeze({
    VERSION, MAP_ROTATION_DEGREES, WORLD_WIDTH, WORLD_HEIGHT, COORD_MIN, COORD_MAX, COORD_CENTER, COORD_SPAN,
    FALKEN_POSITIONS, normalizeCoordinate, coordinateToPixelX, coordinateToPixelY,
    pixelToCoordinateX, pixelToCoordinateY, migrateLegacyCoordinate, positionForSeed, isInBounds
  });
})();
