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
    this.pan = { x: 0, y: 0 };
    this.zoom = 1;
    this.targetZoom = 1;
    this._zoomAnimFrame = null;

    this._setupInteraction();
  }

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

  _autoZoom() {
    if (this.chain.length < 4) {
      this.targetZoom = 1;
    } else {
      const bounds = this.layout.bounds;
      this.targetZoom = getAutoZoom(bounds, this.width, this.height);
    }
    this._animateZoom();
  }

  _animateZoom() {
    if (this._zoomAnimFrame) cancelAnimationFrame(this._zoomAnimFrame);
    const animate = () => {
      const diff = this.targetZoom - this.zoom;
      if (Math.abs(diff) < 0.005) {
        this.zoom = this.targetZoom;
        this.draw();
        return;
      }
      this.zoom += diff * 0.08;
      this.draw();
      this._zoomAnimFrame = requestAnimationFrame(animate);
    };
    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; }

    // Ghost matches the orientation it would have when placed
    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);

    // Convert screen coords to world coords (accounting for pan/zoom)
    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();

    // Empty board: tap anywhere on canvas = center placement
    if (!leftEp && !rightEp) {
      return { end: 'right', value: null };
    }

    // Check which endpoints are active
    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) {
    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;
    }

    const startX = this.width / 2;
    const startY = this.height + 40;
    const duration = 350;
    const startTime = performance.now();

    const animate = (now) => {
      const t = Math.min((now - startTime) / duration, 1);
      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.4 + (1 - 1.4) * ease;

      this.animatingTile = { tile, x, y, w, h, rotation: 0, scale };
      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);

    // Dark background matching app theme
    ctx.fillStyle = '#0f1623';
    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) {
      // Empty board indicator
      ctx.fillStyle = 'rgba(255,255,255,0.08)';
      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 });
    }

    // Draw endpoint indicators (when active for tap-to-confirm)
    this._drawEndpointIndicators(ctx);

    // Ghost tile (during drag)
    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.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) {
    // Subtle grid dots
    ctx.fillStyle = 'rgba(255,255,255,0.02)';
    for (let i = 0; i < this.width; i += 20) {
      for (let j = 0; j < this.height; j += 20) {
        ctx.beginPath();
        ctx.arc(i, j, 1, 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.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._zoomAnimFrame) cancelAnimationFrame(this._zoomAnimFrame);
    this.canvas.remove();
  }
}

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