import { SYMBOLS } from './Symbol.js';

const SYMBOL_HEIGHT = 110;
const SYMBOL_WIDTH = 200;
const VISIBLE_COUNT = 3;
const REEL_HEIGHT = SYMBOL_HEIGHT * VISIBLE_COUNT;
const BUFFER = 2; // extra cells above/below visible area for smooth scroll
const POOL_SIZE = VISIBLE_COUNT + BUFFER * 2;

export class Reel {
  constructor(scene, x, y) {
    this.scene = scene;
    this.x = x;
    this.y = y;
    this.w = SYMBOL_WIDTH;
    this.h = REEL_HEIGHT;

    // Virtual infinite strip: cycle through SYMBOLS array using modulo
    this.strip = SYMBOLS; // reference, never mutated
    this.scrollY = 0;

    // Container with mask for clipping
    this.container = scene.add.container(x, y);
    const maskShape = scene.make.graphics({ add: false });
    maskShape.fillRect(x, y, this.w, this.h);
    this.container.setMask(maskShape.createGeometryMask());

    // Small pool of Graphics + Sprite + Text triples (only as many as visible + buffer)
    this.cells = [];
    for (let i = 0; i < POOL_SIZE; i++) {
      const gfx = scene.add.graphics();
      const spr = scene.add.sprite(0, 0, 'symbols', 0).setOrigin(0.5, 0.5);
      this.container.add(gfx);
      this.container.add(spr);
      this.cells.push({ gfx, spr });
    }

    this._draw();
  }

  // Returns the symbol showing in the center (result) slot
  getCenter() {
    const s = -this.scrollY;
    const centerScrollY = s + SYMBOL_HEIGHT;
    const idx = Math.floor(centerScrollY / SYMBOL_HEIGHT);
    return this.strip[((idx % this.strip.length) + this.strip.length) % this.strip.length];
  }

  _draw() {
    // Negate scrollY so increasing scrollY moves symbols downward (top-to-bottom direction)
    const s = -this.scrollY;
    const topCellIdx = Math.floor(s / SYMBOL_HEIGHT);

    for (let i = 0; i < POOL_SIZE; i++) {
      const virtualIdx = topCellIdx - BUFFER + i;
      const symbolIdx = ((virtualIdx % this.strip.length) + this.strip.length) % this.strip.length;
      const sym = this.strip[symbolIdx];
      const cellY = virtualIdx * SYMBOL_HEIGHT - s;

      const { gfx, spr } = this.cells[i];
      gfx.clear();
      gfx.fillStyle(sym.color, 1);
      gfx.fillRoundedRect(2, cellY + 2, this.w - 4, SYMBOL_HEIGHT - 4, 8);
      gfx.lineStyle(2, 0xffffff, 0.35);
      gfx.strokeRoundedRect(2, cellY + 2, this.w - 4, SYMBOL_HEIGHT - 4, 8);

      spr.setFrame(symbolIdx);
      spr.setPosition(this.w / 2, cellY + SYMBOL_HEIGHT / 2);
    }
  }

  // Spin to targetSymbol. Duration controls how long the fast phase lasts.
  // onComplete fires when the reel finishes.
  spin(targetSymbol, duration, onComplete) {
    const scene = this.scene;

    // Pre-calculate a target scrollY that:
    // - lands targetSymbol in the center slot (scrollY = targetIdx * SYMBOL_HEIGHT - SYMBOL_HEIGHT)
    // - is strictly greater than current scrollY by at least MIN_ADVANCE
    const MIN_ADVANCE = SYMBOL_HEIGHT * 10; // enough for a satisfying visible spin
    const stripHeight = this.strip.length * SYMBOL_HEIGHT;

    const targetSymbolIdx = this.strip.findIndex(s => s.id === targetSymbol.id);
    // With negated draw: center when -scrollY = targetSymbolIdx * SYMBOL_HEIGHT - SYMBOL_HEIGHT
    // => scrollY = SYMBOL_HEIGHT - targetSymbolIdx * SYMBOL_HEIGHT
    let targetScrollY = SYMBOL_HEIGHT - targetSymbolIdx * SYMBOL_HEIGHT;

    // scrollY must DECREASE by at least MIN_ADVANCE (spin goes in negative direction)
    while (targetScrollY >= this.scrollY - MIN_ADVANCE) {
      targetScrollY -= stripHeight;
    }

    // Phase 1: fast linear scroll to ~2 symbols before the final landing
    const fastTarget = targetScrollY + SYMBOL_HEIGHT * 2;

    scene.tweens.add({
      targets: this,
      scrollY: fastTarget,
      duration: duration,
      ease: 'Linear',
      onUpdate: () => this._draw(),
      onComplete: () => {
        // Phase 2: decelerate smoothly into the final position
        scene.tweens.add({
          targets: this,
          scrollY: targetScrollY,
          duration: 650,
          ease: 'Cubic.easeOut',
          onUpdate: () => this._draw(),
          onComplete: () => {
            this.scrollY = targetScrollY;
            this._draw();
            if (onComplete) onComplete();
          }
        });
      }
    });
  }

  getWidth()  { return this.w; }
  getHeight() { return this.h; }
}
