/**
 * Joystick.js
 * Virtual joystick component for touch-based directional control.
 * Positioned at the bottom-left of the screen; overlaid as a separate layer
 * above the map when they intersect.
 */

const {
  DIRECTION,
  SCREEN_WIDTH,
  SCREEN_HEIGHT,
} = require('../base/GameGlobal');

class Joystick {
  constructor() {
    // Position and size — anchored to screen bottom-left, shifted slightly
    // towards the upper-right for comfortable thumb reach
    this.radius = 50;
    this.innerRadius = 20;
    const padding = this.radius + 30;
    this.cx = padding + 15;                  // left edge + rightward offset
    this.cy = SCREEN_HEIGHT - padding - 30;  // bottom edge + upward offset

    // State
    this._active = false;
    this._touchId = null;
    this._touchX = 0;
    this._touchY = 0;
    this._direction = -1; // -1 = no direction
    this._dx = 0;
    this._dy = 0;

    // Touch area (larger than visual for easier use)
    this._touchAreaRadius = this.radius * 2;
  }

  /**
   * Handle touch events.
   * @param {string} eventType
   * @param {Touch} touch - Single touch object.
   * @returns {boolean} Whether this joystick consumed the touch.
   */
  handleTouch(eventType, touch) {
    const tx = touch.clientX;
    const ty = touch.clientY;

    if (eventType === 'touchstart') {
      // Check if touch is within joystick area
      const dist = Math.sqrt((tx - this.cx) ** 2 + (ty - this.cy) ** 2);
      if (dist <= this._touchAreaRadius) {
        this._active = true;
        this._touchId = touch.identifier;
        this._updateDirection(tx, ty);
        return true;
      }
      return false;
    }

    if (eventType === 'touchmove') {
      if (this._active && touch.identifier === this._touchId) {
        this._updateDirection(tx, ty);
        return true;
      }
      return false;
    }

    if (eventType === 'touchend') {
      if (this._active && touch.identifier === this._touchId) {
        this._active = false;
        this._touchId = null;
        this._direction = -1;
        this._dx = 0;
        this._dy = 0;
        return true;
      }
      return false;
    }

    return false;
  }

  /**
   * Calculate direction from touch position.
   * @private
   */
  _updateDirection(tx, ty) {
    this._touchX = tx;
    this._touchY = ty;

    const dx = tx - this.cx;
    const dy = ty - this.cy;
    const dist = Math.sqrt(dx * dx + dy * dy);

    if (dist < 10) {
      this._direction = -1;
      this._dx = 0;
      this._dy = 0;
      return;
    }

    // Clamp to radius for visual
    const clampDist = Math.min(dist, this.radius);
    this._dx = (dx / dist) * clampDist;
    this._dy = (dy / dist) * clampDist;

    // Determine 4-direction based on angle
    const angle = Math.atan2(dy, dx);
    // Right: -45° to 45°, Down: 45° to 135°, Left: 135° to -135°, Up: -135° to -45°
    if (angle >= -Math.PI / 4 && angle < Math.PI / 4) {
      this._direction = DIRECTION.RIGHT;
    } else if (angle >= Math.PI / 4 && angle < Math.PI * 3 / 4) {
      this._direction = DIRECTION.DOWN;
    } else if (angle >= -Math.PI * 3 / 4 && angle < -Math.PI / 4) {
      this._direction = DIRECTION.UP;
    } else {
      this._direction = DIRECTION.LEFT;
    }
  }

  /**
   * Render the joystick.
   * @param {CanvasRenderingContext2D} ctx
   */
  render(ctx) {
    ctx.save();
    ctx.globalAlpha = 0.3;

    // Outer circle
    ctx.fillStyle = '#333333';
    ctx.strokeStyle = '#666666';
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.arc(this.cx, this.cy, this.radius, 0, Math.PI * 2);
    ctx.fill();
    ctx.stroke();

    // Direction indicators
    ctx.globalAlpha = 0.3;
    ctx.fillStyle = '#FFFFFF';
    const arrowSize = 8;
    // Up arrow
    this._drawArrow(ctx, this.cx, this.cy - this.radius * 0.6, DIRECTION.UP, arrowSize);
    // Down arrow
    this._drawArrow(ctx, this.cx, this.cy + this.radius * 0.6, DIRECTION.DOWN, arrowSize);
    // Left arrow
    this._drawArrow(ctx, this.cx - this.radius * 0.6, this.cy, DIRECTION.LEFT, arrowSize);
    // Right arrow
    this._drawArrow(ctx, this.cx + this.radius * 0.6, this.cy, DIRECTION.RIGHT, arrowSize);

    // Inner knob
    ctx.globalAlpha = 0.6;
    const knobX = this._active ? this.cx + this._dx : this.cx;
    const knobY = this._active ? this.cy + this._dy : this.cy;

    ctx.fillStyle = this._active ? '#FFD700' : '#888888';
    ctx.beginPath();
    ctx.arc(knobX, knobY, this.innerRadius, 0, Math.PI * 2);
    ctx.fill();

    ctx.restore();
  }

  /**
   * Draw a small directional arrow.
   * @private
   */
  _drawArrow(ctx, x, y, dir, size) {
    ctx.beginPath();
    switch (dir) {
      case DIRECTION.UP:
        ctx.moveTo(x, y - size);
        ctx.lineTo(x - size, y + size);
        ctx.lineTo(x + size, y + size);
        break;
      case DIRECTION.DOWN:
        ctx.moveTo(x, y + size);
        ctx.lineTo(x - size, y - size);
        ctx.lineTo(x + size, y - size);
        break;
      case DIRECTION.LEFT:
        ctx.moveTo(x - size, y);
        ctx.lineTo(x + size, y - size);
        ctx.lineTo(x + size, y + size);
        break;
      case DIRECTION.RIGHT:
        ctx.moveTo(x + size, y);
        ctx.lineTo(x - size, y - size);
        ctx.lineTo(x - size, y + size);
        break;
    }
    ctx.closePath();
    ctx.fill();
  }

  /** Current direction (-1 if idle). */
  get direction() {
    return this._direction;
  }

  /** Whether the joystick is being touched. */
  get active() {
    return this._active;
  }
}

module.exports = Joystick;
