// PuckSprite — the flying creature + its speech bubble.
// Forms are swappable; the sprite layer mounts standalone in overlay mode.

import * as React from "react";
import type { ReactionKind, StyleTag, Tier } from "../engine";

export type SpriteForm = "mossling" | "wisp" | "gremlin" | "moth";
export type BubbleStyle = "voice" | "plain" | "hand";

// the creature body in a given form (also reused in panels/toasts at small size)
export function SpriteBody({ form = "mossling" }: { form?: SpriteForm }) {
  if (form === "wisp") {
    return (
      <div className="puck-face">
        <div
          className="puck-body"
          style={{
            width: 26,
            height: 26,
            background: "radial-gradient(circle at 40% 35%, #fff7e0, var(--puck-body) 72%)",
          }}
        >
          <div className="puck-eye l" style={{ width: 4, height: 5, top: "42%", left: "33%" }} />
          <div className="puck-eye r" style={{ width: 4, height: 5, top: "42%", right: "33%" }} />
        </div>
        <div
          style={{
            position: "absolute",
            inset: "18%",
            border: "1px solid var(--puck-wing)",
            borderRadius: "50%",
            opacity: 0.6,
          }}
        />
        <div
          style={{
            position: "absolute",
            inset: "4%",
            border: "1px solid var(--puck-wing)",
            borderRadius: "50%",
            opacity: 0.35,
          }}
        />
      </div>
    );
  }
  if (form === "gremlin") {
    return (
      <div className="puck-face">
        <div
          className="puck-wing l"
          style={{ width: 14, height: 22, top: "30%", borderRadius: "40% 10% 10% 40%" }}
        />
        <div
          className="puck-wing r"
          style={{ width: 14, height: 22, top: "30%", borderRadius: "10% 40% 40% 10%" }}
        />
        <div className="puck-body" style={{ width: 30, height: 30, borderRadius: "10px" }}>
          <div className="puck-eye l" style={{ borderRadius: 2, width: 5, height: 6 }} />
          <div className="puck-eye r" style={{ borderRadius: 2, width: 5, height: 6 }} />
          <div
            style={{
              position: "absolute",
              bottom: "22%",
              left: "50%",
              transform: "translateX(-50%)",
              width: 8,
              height: 2,
              background: "#15201a",
              borderRadius: 2,
            }}
          />
        </div>
      </div>
    );
  }
  if (form === "moth") {
    return (
      <div className="puck-face">
        <div
          className="puck-wing l"
          style={{ width: 30, height: 34, top: "34%", borderRadius: "70% 20% 60% 40%" }}
        />
        <div
          className="puck-wing r"
          style={{ width: 30, height: 34, top: "34%", borderRadius: "20% 70% 40% 60%" }}
        />
        <div className="puck-body" style={{ width: 18, height: 30, borderRadius: "50%" }}>
          <div className="puck-eye l" style={{ left: "24%" }} />
          <div className="puck-eye r" style={{ right: "24%" }} />
        </div>
        <div
          style={{
            position: "absolute",
            top: "22%",
            left: "44%",
            width: 1.5,
            height: 9,
            background: "var(--puck-body)",
            transform: "rotate(18deg)",
          }}
        />
        <div
          style={{
            position: "absolute",
            top: "22%",
            right: "44%",
            width: 1.5,
            height: 9,
            background: "var(--puck-body)",
            transform: "rotate(-18deg)",
          }}
        />
      </div>
    );
  }
  // mossling (default)
  return (
    <div className="puck-face">
      <div className="puck-wing l" />
      <div className="puck-wing r" />
      <div className="puck-body">
        <div className="puck-eye l" />
        <div className="puck-eye r" />
        <div className="puck-cheek l" />
        <div className="puck-cheek r" />
      </div>
    </div>
  );
}

export interface SpriteState {
  x: number;
  y: number;
  flying: boolean;
  resting: boolean;
  facing: "left" | "right";
}

export function PuckSprite({
  sprite,
  form,
  speaking,
  alert = false,
  reaction = null,
  shout,
  reactKey = 0,
  muted = false,
  camo = false,
  onPoke,
  onMenu,
}: {
  sprite: SpriteState;
  form: SpriteForm;
  speaking: boolean;
  /** Something is waiting (bubble/toast/interrupt) — pulse to draw the eye,
   *  the overlay's answer to a sprite lost on a busy desktop. */
  alert?: boolean;
  /** Muted: watching but silent — calm the glow and show a 🔇 badge. */
  muted?: boolean;
  /** Camo: blended into the desktop — glassy/transparent skin, faint eyes. */
  camo?: boolean;
  /** One-shot personality gesture (null between reactions). */
  reaction?: ReactionKind | null;
  /** Optional exclamation that floats over the sprite during the reaction. */
  shout?: string;
  /** Monotonic counter — bumping it remounts the animated layers so the SAME
   *  reaction restarts its CSS animation (back-to-back pushes still pop). */
  reactKey?: number;
  onPoke: () => void;
  /** Right-click — the overlay has no menu bar, so the sprite IS the menu. */
  onMenu?: () => void;
}) {
  const cls = ["puck"];
  if (sprite.flying) cls.push("flying", "snappy");
  if (sprite.resting) cls.push("resting");
  if (sprite.facing === "left") cls.push("face-left");
  if (speaking) cls.push("speaking");
  if (alert) cls.push("alert");
  if (reaction) cls.push(`react-${reaction}`);
  if (muted) cls.push("muted");
  if (camo) cls.push("camo");
  return (
    <div className={cls.join(" ")} style={{ transform: `translate(${sprite.x - 32}px, ${sprite.y - 32}px)` }}>
      {shout && (
        // sibling of .puck-bob so the body's scale/spin doesn't warp the text
        <div className="puck-shout" key={reactKey}>
          {shout}
        </div>
      )}
      <div className="puck-bob" key={reactKey}>
        <div className="puck-glow" />
        <div className="puck-alert-ring" />
        <div className="puck-trail" />
        <div className="puck-voicewave">
          <i />
          <i />
          <i />
        </div>
        <SpriteBody form={form} />
        {muted && <div className="puck-mute">🔇</div>}
        <div
          className="puck-hit"
          onClick={onPoke}
          onContextMenu={(e) => {
            if (!onMenu) return;
            e.preventDefault();
            onMenu();
          }}
          title="poke Puck · right-click for menu"
        />
      </div>
    </div>
  );
}

// ---- speech bubble ----------------------------------------------------------

export interface BubbleData {
  uid: string;
  source: string;
  text: string;
  tier: Tier;
  tags: StyleTag[];
  x: number;
  y: number;
  ratable: boolean;
}

export function Bubble({
  data,
  bubbleStyle,
  onRate,
  onDismiss,
}: {
  data: BubbleData;
  bubbleStyle: BubbleStyle;
  onRate: (rating: "helpful" | "annoying" | "cute") => void;
  onDismiss: () => void;
}) {
  const [out, setOut] = React.useState(false);
  const W = 290;
  const vw = window.innerWidth;
  const vh = window.innerHeight;
  const below = data.y < 250;
  const left = Math.max(12, Math.min(vw - W - 12, data.x - 40));
  const style: React.CSSProperties = below
    ? { left, top: data.y + 46 }
    : { left, top: "auto", bottom: vh - data.y + 46 };
  const tailX = Math.max(16, Math.min(W - 28, data.x - left - 7));

  const dismiss = (rating?: "helpful" | "annoying" | "cute") => {
    setOut(true);
    setTimeout(() => {
      if (rating) onRate(rating);
      else onDismiss();
    }, 260);
  };

  const styleCls = { voice: "", plain: "style-plain", hand: "style-hand" }[bubbleStyle];
  return (
    <div className={`bubble ${styleCls} ${out ? "out" : ""}`} style={{ ...style, width: W }}>
      <div
        className="bub-tail"
        style={
          below
            ? { top: -7, left: tailX, transform: "rotate(135deg)" }
            : { bottom: -7, left: tailX, transform: "rotate(45deg)" }
        }
      />
      <div className="bub-src">
        <span>{data.source ? `Puck · ${data.source}` : "Puck"}</span>
        <span className="bub-tier">
          {data.tier === "mythic" ? "✦ theatrical" : data.tier === "plain" ? "plain" : "playful"}
        </span>
      </div>
      <div className="bub-text">{data.text}</div>
      {data.ratable && (
        <div className="bub-acts">
          <button type="button" className="bub-rate" onClick={() => dismiss("helpful")}>
            👍 helpful
          </button>
          <button type="button" className="bub-rate" onClick={() => dismiss("annoying")}>
            🙄 annoying
          </button>
          <button type="button" className="bub-rate" onClick={() => dismiss("cute")}>
            🌸 cute, useless
          </button>
        </div>
      )}
    </div>
  );
}
