/* ============================================================
   sprites.js - All characters & LCD segments drawn procedurally
   on the canvas. Style: flat black "liquid-crystal" silhouettes,
   matching the SP-30 Snoopy Tennis display.
   Every draw fn works in the canvas' 600x400 coordinate space.
   ============================================================ */
(function (ST) {
  "use strict";

  var SEG = "#2b2b26";      // lit segment
  var GHOST = "#9aa07f2e";  // faint "off" segment ghost (subtle)

  /* --- PNG drawing (with graceful fallback to vectors) ---
     Draws image `imgKey` using placement config `cfgKey`, anchored at
     (cx, cy). anchor: "feet" (bottom-centre) | "center" | "topleft".
     Returns true if the image was drawn, false if unavailable. */
  function drawImg(ctx, imgKey, cfgKey, cx, cy, anchor) {
    var img = ST.Assets && ST.Assets.get(imgKey);
    if (!img) return false;
    var c = ST.cfg ? ST.cfg(cfgKey) : { scale: 1, dx: 0, dy: 0 };
    var s = c.scale || 1;
    var w = img.naturalWidth * s, h = img.naturalHeight * s;
    var x, y;
    if (anchor === "center")      { x = cx - w / 2; y = cy - h / 2; }
    else if (anchor === "topleft"){ x = cx;         y = cy;         }
    else /* feet: bottom-centre */{ x = cx - w / 2; y = cy - h;     }
    ctx.drawImage(img, x + (c.dx || 0), y + (c.dy || 0), w, h);
    return true;
  }

  function poly(ctx, pts) {
    ctx.beginPath();
    ctx.moveTo(pts[0][0], pts[0][1]);
    for (var i = 1; i < pts.length; i++) ctx.lineTo(pts[i][0], pts[i][1]);
    ctx.closePath();
    ctx.fill();
  }

  /* --- Seven-segment style digit for score/clock --- */
  var SEGMENTS = {
    //     a  b  c  d  e  f  g
    "0": [1,1,1,1,1,1,0],
    "1": [0,1,1,0,0,0,0],
    "2": [1,1,0,1,1,0,1],
    "3": [1,1,1,1,0,0,1],
    "4": [0,1,1,0,0,1,1],
    "5": [1,0,1,1,0,1,1],
    "6": [1,0,1,1,1,1,1],
    "7": [1,1,1,0,0,0,0],
    "8": [1,1,1,1,1,1,1],
    "9": [1,1,1,1,0,1,1],
    " ": [0,0,0,0,0,0,0]
  };

  function digit(ctx, ch, x, y, w, h) {
    var s = SEGMENTS[ch] || SEGMENTS[" "];
    var t = Math.max(2, w * 0.16);       // thickness
    var mx = x + w, my = y + h, midY = y + h / 2;
    ctx.fillStyle = SEG;
    // horizontal seg helper
    function hseg(cy) { poly(ctx, [[x+t,cy-t/2],[mx-t,cy-t/2],[mx-t*0.5,cy],[mx-t,cy+t/2],[x+t,cy+t/2],[x+t*0.5,cy]]); }
    function vseg(cx, y1, y2) { poly(ctx, [[cx,y1+t*0.5],[cx+t/2,y1+t],[cx+t/2,y2-t],[cx,y2-t*0.5],[cx-t/2,y2-t],[cx-t/2,y1+t]]); }
    if (s[0]) hseg(y);            // a top
    if (s[3]) hseg(my);          // d bottom
    if (s[6]) hseg(midY);        // g middle
    if (s[5]) vseg(x, y, midY);  // f top-left
    if (s[4]) vseg(x, midY, my); // e bottom-left
    if (s[1]) vseg(mx, y, midY); // b top-right
    if (s[2]) vseg(mx, midY, my);// c bottom-right
  }

  function number(ctx, str, x, y, w, h, gap) {
    gap = gap || w * 0.35;
    for (var i = 0; i < str.length; i++) {
      digit(ctx, str[i], x + i * (w + gap), y, w, h);
    }
  }

  /* ============ CHARACTERS ============ */

  /* Snoopy - beagle facing LEFT, standing on the tree, holding a racket.
     frame: 0 = ready (racket back), 1 = swing (racket forward/up). */
  function snoopy(ctx, cx, cy, frame, ghost) {
    if (drawImg(ctx, frame === 1 ? "snoopy_swing" : "snoopy_ready", "snoopy", cx, cy, "feet")) return;
    ctx.save();
    ctx.translate(cx, cy);
    ctx.fillStyle = ghost ? GHOST : SEG;
    // Body (upright), anchor at feet (0,0)
    // legs
    poly(ctx, [[-9,0],[-2,0],[-3,-16],[-9,-16]]);
    poly(ctx, [[4,0],[11,0],[9,-16],[3,-16]]);
    // torso
    poly(ctx, [[-11,-15],[11,-15],[13,-40],[-9,-44]]);
    // white belly cut
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    poly(ctx, [[-4,-16],[7,-16],[8,-36],[-2,-38]]);
    ctx.restore();
    // head - snout pointing left
    ctx.beginPath();
    ctx.ellipse(-6, -52, 20, 15, 0, 0, Math.PI * 2);
    ctx.fill();
    // ear hanging
    ctx.beginPath();
    ctx.ellipse(2, -46, 7, 12, -0.3, 0, Math.PI * 2);
    ctx.fill();
    // snout tip
    ctx.beginPath();
    ctx.ellipse(-24, -50, 7, 5, 0, 0, Math.PI * 2);
    ctx.fill();
    // eye (cut white)
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    ctx.beginPath(); ctx.ellipse(-10, -55, 3.5, 5, 0, 0, Math.PI*2); ctx.fill();
    // white face patch
    ctx.beginPath(); ctx.ellipse(-2, -50, 9, 9, 0, 0, Math.PI*2); ctx.fill();
    ctx.restore();
    ctx.beginPath(); ctx.arc(-10, -55, 2.2, 0, Math.PI*2); ctx.fill(); // pupil
    // arm + racket
    ctx.save();
    ctx.strokeStyle = ghost ? GHOST : SEG;
    ctx.lineWidth = 5; ctx.lineCap = "round";
    if (frame === 1) {
      // swing forward (racket to the left, extended)
      ctx.beginPath(); ctx.moveTo(-8, -34); ctx.lineTo(-30, -30); ctx.stroke();
      racket(ctx, -40, -26, -0.5, ghost);
    } else {
      // ready (racket up/back)
      ctx.beginPath(); ctx.moveTo(8, -34); ctx.lineTo(22, -46); ctx.stroke();
      racket(ctx, 28, -54, 0.6, ghost);
    }
    ctx.restore();
    ctx.restore();
  }

  function racket(ctx, x, y, rot, ghost) {
    ctx.save();
    ctx.translate(x, y); ctx.rotate(rot);
    ctx.fillStyle = ghost ? GHOST : SEG;
    ctx.beginPath(); ctx.ellipse(0, 0, 11, 8, 0, 0, Math.PI * 2); ctx.fill();
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    ctx.beginPath(); ctx.ellipse(0, 0, 7.5, 5, 0, 0, Math.PI * 2); ctx.fill();
    ctx.restore();
    // strings
    ctx.strokeStyle = ghost ? GHOST : SEG; ctx.lineWidth = 1;
    for (var i = -6; i <= 6; i += 4) {
      ctx.beginPath(); ctx.moveTo(i, -4); ctx.lineTo(i, 4); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(-8, i*0.6); ctx.lineTo(8, i*0.6); ctx.stroke();
    }
    ctx.restore();
  }

  /* Charlie Brown - facing RIGHT, serving from bottom-left.
     frame: 0 ready, 1 just-served (arm up). */
  function charlie(ctx, cx, cy, frame, ghost) {
    if (drawImg(ctx, frame === 1 ? "charlie_serve" : "charlie_ready", "charlie", cx, cy, "feet")) return;
    ctx.save();
    ctx.translate(cx, cy);
    ctx.fillStyle = ghost ? GHOST : SEG;
    // legs
    poly(ctx, [[-8,0],[-2,0],[-3,-14],[-8,-14]]);
    poly(ctx, [[3,0],[9,0],[8,-14],[3,-14]]);
    // shirt (zig-zag body)
    poly(ctx, [[-11,-13],[11,-13],[10,-34],[-10,-34]]);
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    // zig-zag stripe cut
    ctx.beginPath();
    ctx.moveTo(-10,-22); ctx.lineTo(-5,-25); ctx.lineTo(0,-22); ctx.lineTo(5,-25);
    ctx.lineTo(10,-22); ctx.lineTo(10,-27); ctx.lineTo(-10,-27);
    ctx.closePath(); ctx.fill();
    ctx.restore();
    // big round head
    ctx.beginPath(); ctx.arc(0, -46, 15, 0, Math.PI * 2); ctx.fill();
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    ctx.beginPath(); ctx.arc(2, -46, 11, 0, Math.PI*2); ctx.fill(); // face
    ctx.restore();
    // eyes/curl
    ctx.beginPath(); ctx.arc(5, -49, 1.6, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(-1, -49, 1.6, 0, Math.PI*2); ctx.fill();
    poly(ctx, [[-10,-56],[-2,-58],[-3,-54]]); // hair curl
    // arm + racket
    ctx.strokeStyle = ghost ? GHOST : SEG; ctx.lineWidth = 4.5; ctx.lineCap = "round";
    if (frame === 1) {
      ctx.beginPath(); ctx.moveTo(8,-30); ctx.lineTo(24,-42); ctx.stroke();
      racket(ctx, 30, -48, -0.5, ghost);
    } else {
      ctx.beginPath(); ctx.moveTo(9,-28); ctx.lineTo(20,-20); ctx.stroke();
      racket(ctx, 26, -16, 0.4, ghost);
    }
    ctx.restore();
  }

  /* Lucy - on her platform, facing RIGHT/down, smashing.
     frame 0 idle, 1 smash. */
  function lucy(ctx, cx, cy, frame, ghost) {
    if (drawImg(ctx, frame === 1 ? "lucy_smash" : "lucy_idle", "lucy", cx, cy, "feet")) return;
    ctx.save();
    ctx.translate(cx, cy);
    ctx.fillStyle = ghost ? GHOST : SEG;
    // legs
    poly(ctx, [[-7,0],[-2,0],[-3,-12],[-7,-12]]);
    poly(ctx, [[3,0],[8,0],[7,-12],[3,-12]]);
    // dress (triangle)
    poly(ctx, [[-13,-11],[13,-11],[7,-33],[-7,-33]]);
    // head
    ctx.beginPath(); ctx.arc(0, -42, 12, 0, Math.PI * 2); ctx.fill();
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    ctx.beginPath(); ctx.arc(2, -42, 8.5, 0, Math.PI*2); ctx.fill();
    ctx.restore();
    // hair flip
    poly(ctx, [[-12,-44],[-4,-52],[2,-46],[-6,-40]]);
    ctx.beginPath(); ctx.arc(4, -44, 1.5, 0, Math.PI*2); ctx.fill(); // eye
    // arm + racket (smashing down-right)
    ctx.strokeStyle = ghost ? GHOST : SEG; ctx.lineWidth = 4; ctx.lineCap = "round";
    if (frame === 1) {
      ctx.beginPath(); ctx.moveTo(9,-26); ctx.lineTo(26,-30); ctx.stroke();
      racket(ctx, 33, -30, 0.1, ghost);
    } else {
      ctx.beginPath(); ctx.moveTo(9,-26); ctx.lineTo(20,-40); ctx.stroke();
      racket(ctx, 25, -46, 0.7, ghost);
    }
    ctx.restore();
  }

  /* Tennis ball */
  function ball(ctx, x, y, r, ghost) {
    if (drawImg(ctx, "ball", "ball", x, y, "center")) return;
    ctx.save();
    ctx.fillStyle = ghost ? GHOST : SEG;
    ctx.beginPath(); ctx.arc(x, y, r || 6, 0, Math.PI * 2); ctx.fill();
    ctx.restore();
  }

  /* Woodstock in the nest */
  function woodstock(ctx, x, y, ghost) {
    if (drawImg(ctx, "woodstock", "woodstock", x, y, "center")) return;
    ctx.save();
    ctx.fillStyle = ghost ? GHOST : SEG;
    ctx.beginPath(); ctx.arc(x, y, 4, 0, Math.PI*2); ctx.fill();      // body
    poly(ctx, [[x-4,y-4],[x-1,y-9],[x+1,y-6]]);                       // tuft
    poly(ctx, [[x+3,y-1],[x+9,y-2],[x+3,y+2]]);                       // beak
    ctx.restore();
  }

  /* MISS markers - broken bottle icons (as in original) */
  function missMark(ctx, x, y, ghost) {
    if (drawImg(ctx, ghost ? "miss_unlit" : "miss_lit", "missMark", x, y, "topleft")) return;
    ctx.save();
    ctx.fillStyle = ghost ? GHOST : SEG;
    poly(ctx, [[x,y],[x+3,y-8],[x+7,y-8],[x+9,y],[x+9,y+4],[x,y+4]]); // bottle body
    poly(ctx, [[x+3,y-8],[x+2,y-13],[x+5,y-15],[x+7,y-11],[x+7,y-8]]);// neck
    // crack
    ctx.save(); ctx.globalCompositeOperation = "destination-out";
    ctx.beginPath(); ctx.moveTo(x+4,y-4); ctx.lineTo(x+6,y-1); ctx.lineTo(x+4,y+2);
    ctx.lineWidth=1; ctx.strokeStyle="#000"; ctx.stroke();
    ctx.restore();
    ctx.restore();
  }

  ST.Sprites = {
    SEG: SEG, GHOST: GHOST,
    snoopy: snoopy, charlie: charlie, lucy: lucy, ball: ball,
    woodstock: woodstock, missMark: missMark,
    number: number, digit: digit,
    image: drawImg          // generic: (ctx, imgKey, cfgKey, x, y, anchor)
  };
})(window.ST = window.ST || {});
