import { createCanvas, clear } from '../../../core/canvas.js';
import { computeLayout, hitTestEndpoint, getSnapRadius, getAutoZoom } from '../logic/layout.js';
import { drawTile, drawEndpointGlow } from './tile-renderer.js';
import { TILE_W, TILE_H } from '../logic/layout.js';

export class DominoBoard {
  constructor(container, options = {}) {
    this.container = container;
    this.onEndpointTap = options.onEndpointTap || null;

    const rect = container.getBoundingClientRect();
    this.width = rect.width || 370;
    this.height = rect.height || 400;

    const { canvas, ctx } = createCanvas(container, this.width, this.height);
    canvas.style.cssText = 'width:100%;height:100%;border-radius:12px;touch-action:none;';
    this.canvas = canvas;
    this.ctx = ctx;

    this.chain = [];
    this.layout = { tiles: [], endpoints: { left: null, right: null }, bounds: {} };
    this.ghost = null;
    this.activeEndpoint = null;
    this.animatingTile = null;

    // Pan & zoom state — smooth animated transitions
    this.pan = { x: 0, y: 0 };
    this.targetPan = { x: 0, y: 0 };
    this.zoom = 1;
    this.targetZoom = 1;
    this._animFrame = null;
    this._isAnimating = false;

    this._setupInteraction();
  }

  setChain(chain) {
    this.chain = chain;
    this.layout = computeLayout(chain, this.width, this.height);
    this._autoFit();
    this.draw();
  }

  _autoFit() {
    if (this.chain.length < 2) {
      this.targetZoom = 1;
      this.targetPan = { x: 0, y: 0 };
    } else {
      const bounds = this.layout.bounds;
      this.targetZoom = getAutoZoom(bounds, this.width, this.height);

      // Auto-center on the chain
      const chainCenterX = (bounds.minX + bounds.maxX) / 2;
      const chainCenterY = (bounds.minY + bounds.maxY) / 2;
      this.targetPan = {
        x: chainCenterX - this.width / 2,
        y: chainCenterY - this.height / 2
      };
    }
    this._startSmoothTransition();
  }

  _startSmoothTransition() {
    if (this._isAnimating) return;
    this._isAnimating = true;
    this._animate();
  }

  _animate() {
    const panDiffX = this.targetPan.x - this.pan.x;
    const panDiffY = this.targetPan.y - this.pan.y;
    const zoomDiff = this.targetZoom - this.zoom;

    const threshold = 0.003;
    const settled = Math.abs(panDiffX) < 0.5 && Math.abs(panDiffY) < 0.5 && Math.abs(zoomDiff) < threshold;

    if (settled) {
      this.pan.x = this.targetPan.x;
      this.pan.y = this.targetPan.y;
      this.zoom = this.targetZoom;
      this._isAnimating = false;
      this.draw();
      return;
    }

    // Smooth lerp (ease-out feel)
    const speed = 0.1;
    this.pan.x += panDiffX * speed;
    this.pan.y += panDiffY * speed;
    this.zoom += zoomDiff * speed;

    this.draw();
    this._animFrame = requestAnimationFrame(() => this._animate());
  }

  setGhost(tile, end, valid) {
    if (!tile || !end) { this.ghost = null; this.draw(); return; }
    const ep = end === 'left' ? this.layout.endpoints.left : this.layout.endpoints.right;
    if (!ep) { this.ghost = null; this.draw(); return; }

    const dbl = tile.left === tile.right;
    const lastTileIdx = end === 'left' ? 0 : this.layout.tiles.length - 1;
    const lt = this.layout.tiles[lastTileIdx];
    const isHorizontal = lt ? (lt.dirIdx === 0 || lt.dirIdx === 2) : true;

    let w, h;
    if (isHorizontal) {
      w = dbl ? TILE_W : TILE_H;
      h = dbl ? TILE_H : TILE_W;
    } else {
      w = dbl ? TILE_H : TILE_W;
      h = dbl ? TILE_W : TILE_H;
    }

    this.ghost = { tile, x: ep.x, y: ep.y, w, h, rotation: 0, valid };
    this.draw();
  }

  clearGhost() {
    this.ghost = null;
    this.draw();
  }

  setActiveEndpoint(end) {
    this.activeEndpoint = end;
    this.draw();
  }

  clearActiveEndpoint() {
    this.activeEndpoint = null;
    this.draw();
  }

  getEndpointScreenPos(end) {
    const ep = end === 'left' ? this.layout.endpoints.left : this.layout.endpoints.right;
    if (!ep) return null;
    const rect = this.canvas.getBoundingClientRect();
    const scaleX = rect.width / this.width;
    const scaleY = rect.height / this.height;
    const cx = this.width / 2 + this.pan.x;
    const cy = this.height / 2 + this.pan.y;
    const sx = (ep.x - cx) * this.zoom + this.width / 2;
    const sy = (ep.y - cy) * this.zoom + this.height / 2;
    return { x: rect.left + sx * scaleX, y: rect.top + sy * scaleY, value: ep.value };
  }

  hitTestEndpoints(screenX, screenY) {
    if (!this.activeEndpoint) return null;

    const rect = this.canvas.getBoundingClientRect();
    const canvasX = (screenX - rect.left) * (this.width / rect.width);
    const canvasY = (screenY - rect.top) * (this.height / rect.height);

    const cx = this.width / 2 + this.pan.x;
    const cy = this.height / 2 + this.pan.y;
    const worldX = (canvasX - this.width / 2) / this.zoom + cx;
    const worldY = (canvasY - this.height / 2) / this.zoom + cy;

    const leftEp = this.layout.endpoints.left;
    const rightEp = this.layout.endpoints.right;
    const radius = getSnapRadius();

    if (!leftEp && !rightEp) {
      return { end: 'right', value: null };
    }

    const checkLeft = this.activeEndpoint === 'left' || this.activeEndpoint === 'both';
    const checkRight = this.activeEndpoint === 'right' || this.activeEndpoint === 'both';

    if (checkLeft && leftEp && dist(worldX, worldY, leftEp.x, leftEp.y) < radius) {
      return { end: 'left', value: leftEp.value };
    }
    if (checkRight && rightEp && dist(worldX, worldY, rightEp.x, rightEp.y) < radius) {
      return { end: 'right', value: rightEp.value };
    }
    return null;
  }

  animatePlacement(tile, end, callback, fromPlayer = 'me') {
    const ep = end === 'left' ? this.layout.endpoints.left : this.layout.endpoints.right;
    if (!ep) { callback?.(); return; }

    const dbl = tile.left === tile.right;
    const lastTileIdx = end === 'left' ? 0 : this.layout.tiles.length - 1;
    const lt = this.layout.tiles[lastTileIdx];
    const isHorizontal = lt ? (lt.dirIdx === 0 || lt.dirIdx === 2) : true;

    let w, h;
    if (isHorizontal) {
      w = dbl ? TILE_W : TILE_H;
      h = dbl ? TILE_H : TILE_W;
    } else {
      w = dbl ? TILE_H : TILE_W;
      h = dbl ? TILE_W : TILE_H;
    }

    // Animate from the correct player's side
    const startX = this.width / 2;
    const startY = fromPlayer === 'me' ? this.height + 40 : -40;
    const duration = 350;
    const startTime = performance.now();

    const animate = (now) => {
      const t = Math.min((now - startTime) / duration, 1);
      // Ease out back (slight overshoot for satisfying snap)
      const ease = 1 - Math.pow(1 - t, 3);

      const x = startX + (ep.x - startX) * ease;
      const y = startY + (ep.y - startY) * ease;
      const scale = 1.3 + (1 - 1.3) * ease;
      const alpha = 0.3 + 0.7 * ease;

      this.animatingTile = { tile, x, y, w, h, rotation: 0, scale, alpha };
      this.draw();

      if (t < 1) {
        requestAnimationFrame(animate);
      } else {
        this.animatingTile = null;
        callback?.();
      }
    };
    requestAnimationFrame(animate);
  }

  draw() {
    const ctx = this.ctx;
    clear(ctx, this.width, this.height);

    // Board background with subtle felt texture
    ctx.fillStyle = '#0b1520';
    ctx.fillRect(0, 0, this.width, this.height);

    // Vignette
    const vg = ctx.createRadialGradient(
      this.width/2, this.height/2, this.height * 0.3,
      this.width/2, this.height/2, this.height * 0.7
    );
    vg.addColorStop(0, 'transparent');
    vg.addColorStop(1, 'rgba(0,0,0,0.3)');
    ctx.fillStyle = vg;
    ctx.fillRect(0, 0, this.width, this.height);

    // Subtle pattern
    this._drawPattern(ctx);

    // Apply pan/zoom transform
    ctx.save();
    const cx = this.width / 2;
    const cy = this.height / 2;
    ctx.translate(cx, cy);
    ctx.scale(this.zoom, this.zoom);
    ctx.translate(-cx - this.pan.x, -cy - this.pan.y);

    if (this.chain.length === 0) {
      ctx.fillStyle = 'rgba(255,255,255,0.06)';
      ctx.font = '600 13px system-ui, sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText('ضع أول قطعة', this.width / 2, this.height / 2);
      this._drawCenterGlow(ctx);
      ctx.restore();
      return;
    }

    // Draw chain tiles
    for (const lt of this.layout.tiles) {
      drawTile(ctx, lt.x, lt.y, lt.w, lt.h, lt.tile, { rotation: 0, flipPips: lt.flipPips });
    }

    // Endpoint indicators
    this._drawEndpointIndicators(ctx);

    // Ghost tile
    if (this.ghost) {
      drawTile(ctx, this.ghost.x, this.ghost.y, this.ghost.w, this.ghost.h,
        this.ghost.tile, { rotation: this.ghost.rotation, ghost: true, invalid: !this.ghost.valid });
    }

    // Animating tile
    if (this.animatingTile) {
      const at = this.animatingTile;
      ctx.save();
      ctx.globalAlpha = at.alpha ?? 1;
      ctx.translate(at.x, at.y);
      ctx.scale(at.scale, at.scale);
      ctx.translate(-at.x, -at.y);
      drawTile(ctx, at.x, at.y, at.w, at.h, at.tile, { rotation: at.rotation });
      ctx.restore();
    }

    ctx.restore();
  }

  _drawPattern(ctx) {
    ctx.fillStyle = 'rgba(255,255,255,0.015)';
    for (let i = 0; i < this.width; i += 24) {
      for (let j = 0; j < this.height; j += 24) {
        ctx.beginPath();
        ctx.arc(i, j, 0.8, 0, Math.PI * 2);
        ctx.fill();
      }
    }
  }

  _drawCenterGlow(ctx) {
    const x = this.width / 2, y = this.height / 2;
    drawEndpointGlow(ctx, x, y, getSnapRadius(), true);
  }

  _drawEndpointIndicators(ctx) {
    const leftEp = this.layout.endpoints.left;
    const rightEp = this.layout.endpoints.right;

    if (this.activeEndpoint === 'left' || this.activeEndpoint === 'both') {
      if (leftEp) drawEndpointGlow(ctx, leftEp.x, leftEp.y, getSnapRadius(), true);
    }
    if (this.activeEndpoint === 'right' || this.activeEndpoint === 'both') {
      if (rightEp) drawEndpointGlow(ctx, rightEp.x, rightEp.y, getSnapRadius(), true);
    }
  }

  _setupInteraction() {
    let startX, startY, isPanning = false;
    let lastPanX = 0, lastPanY = 0;

    this.canvas.addEventListener('pointerdown', (e) => {
      startX = e.clientX;
      startY = e.clientY;
      lastPanX = this.pan.x;
      lastPanY = this.pan.y;
      isPanning = false;
      e.preventDefault();
    });

    this.canvas.addEventListener('pointermove', (e) => {
      if (startX === undefined) return;
      const dx = e.clientX - startX;
      const dy = e.clientY - startY;
      if (Math.abs(dx) + Math.abs(dy) > 8) {
        isPanning = true;
        this.pan.x = lastPanX - dx / this.zoom;
        this.pan.y = lastPanY - dy / this.zoom;
        this.targetPan.x = this.pan.x;
        this.targetPan.y = this.pan.y;
        this.draw();
      }
    });

    this.canvas.addEventListener('pointerup', (e) => {
      if (!isPanning && startX !== undefined && this.onEndpointTap) {
        const hit = this.hitTestEndpoints(e.clientX, e.clientY);
        if (hit) this.onEndpointTap(hit);
      }
      startX = undefined;
      isPanning = false;
    });

    this.canvas.addEventListener('pointercancel', () => {
      startX = undefined;
      isPanning = false;
    });
  }

  destroy() {
    if (this._animFrame) cancelAnimationFrame(this._animFrame);
    this.canvas.remove();
  }
}

function dist(x1, y1, x2, y2) {
  return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
}
