/* Sosh Insider — Bali :: shared chrome primitives */
const { useState, useRef, useEffect, useCallback } = React;

/* ---------- Mac window ---------- */
function useDrag(initial) {
  const [pos, setPos] = useState(initial);
  const start = useRef(null);
  const onDown = (e) => {
    if (e.target.closest("[data-clickable]")) return; // don't drag from buttons
    const pt = e.touches ? e.touches[0] : e;
    start.current = { mx: pt.clientX, my: pt.clientY, ox: pos.x, oy: pos.y };
    const move = (ev) => {
      const p = ev.touches ? ev.touches[0] : ev;
      setPos({
        x: start.current.ox + (p.clientX - start.current.mx),
        y: Math.max(28, start.current.oy + (p.clientY - start.current.my)),
      });
    };
    const up = () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
      window.removeEventListener("touchmove", move);
      window.removeEventListener("touchend", up);
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
    window.addEventListener("touchmove", move, { passive: true });
    window.addEventListener("touchend", up);
  };
  return [pos, onDown, setPos];
}

function MacWindow({
  title,
  onClose,
  onZoom,
  active = true,
  children,
  style,
  className = "",
  bodyClass = "",
  zoomable = true,
  closeable = true,
  onTitleDown,
}) {
  return (
    <div className={"win " + className} style={style}>
      <div
        className={"titlebar" + (active ? "" : " inactive")}
        data-win-drag
        onMouseDown={onTitleDown}
        onTouchStart={onTitleDown}
        style={{ cursor: onTitleDown ? "move" : "default" }}
      >
        {closeable ? (
          <div
            className="tb-box close"
            data-clickable
            title="Close"
            onClick={(e) => {
              e.stopPropagation();
              window.SFX && SFX.close();
              onClose && onClose();
            }}
          />
        ) : (
          <div style={{ width: 14 }} />
        )}
        <div className="tb-spacer" />
        <div className="title-text" title={title}>
          {title}
        </div>
        <div className="tb-spacer" />
        {zoomable ? (
          <div
            className="tb-box zoom"
            data-clickable
            title="Zoom"
            onClick={(e) => {
              e.stopPropagation();
              window.SFX && SFX.click();
              onZoom && onZoom();
            }}
          />
        ) : (
          <div style={{ width: 14 }} />
        )}
      </div>
      <div
        className={"win-body " + bodyClass}
        style={{ flex: "1 1 auto", display: "flex", flexDirection: "column", minHeight: 0 }}
      >
        {children}
      </div>
    </div>
  );
}

/* ---------- Pixel button ---------- */
function PixelButton({ children, onClick, accent, style, title }) {
  return (
    <button
      className={"pbtn" + (accent ? " accent" : "")}
      title={title}
      style={style}
      onClick={(e) => {
        window.SFX && SFX.click();
        onClick && onClick(e);
      }}
    >
      {children}
    </button>
  );
}

/* ---------- Photo (real image, or striped placeholder) ---------- */
function PhotoPlaceholder({ frame, tint, showCaption = false, big = false }) {
  const stripe =
    "repeating-linear-gradient(135deg, rgba(43,38,34,0.05) 0 7px, rgba(43,38,34,0.0) 7px 14px)";

  // Real photograph branch: render the actual image at its natural aspect.
  if (frame && frame.url) {
    return <RealPhoto frame={frame} tint={tint} showCaption={showCaption} big={big} stripe={stripe} />;
  }

  return (
    <div
      className="ph"
      style={{
        position: "relative",
        width: "100%",
        aspectRatio: frame.ar,
        background:
          stripe +
          ", linear-gradient(135deg, " +
          hexA(tint, 0.16) +
          ", " +
          hexA(tint, 0.05) +
          ")",
        backgroundColor: "var(--paper2)",
        border: "1px solid var(--line)",
        overflow: "hidden",
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        color: "var(--ink-soft)",
      }}
    >
      <div
        style={{
          position: "absolute",
          inset: big ? 10 : 6,
          border: "1px dashed rgba(43,38,34,0.35)",
        }}
      />
      <div
        className="mono"
        style={{
          fontSize: big ? 22 : 15,
          lineHeight: 1,
          letterSpacing: 1,
          color: "var(--ink)",
          opacity: 0.75,
          zIndex: 1,
          textAlign: "center",
        }}
      >
        ◳ FRAME {frame.n}
      </div>
      <div
        className="mono"
        style={{
          fontSize: big ? 13 : 11,
          marginTop: 4,
          opacity: 0.5,
          zIndex: 1,
        }}
      >
        {frame.ar.replace(/ /g, "")}
      </div>
      {showCaption && (
        <div
          className="serif"
          style={{
            position: "absolute",
            bottom: 8,
            left: 0,
            right: 0,
            textAlign: "center",
            fontStyle: "italic",
            fontSize: big ? 15 : 12,
            color: "var(--ink-soft)",
            zIndex: 1,
          }}
        >
          “{frame.caption}”
        </div>
      )}
      {/* corner sprockets to read as film */}
      <Sprockets />
    </div>
  );
}

/* ---------- Real photograph ---------- */
function RealPhoto({ frame, tint, showCaption, big, stripe }) {
  const [loaded, setLoaded] = useState(false);
  const [failed, setFailed] = useState(false);

  if (failed) {
    // URL didn't resolve (e.g. not uploaded yet / wrong folder name).
    return (
      <div
        style={{
          position: "relative",
          width: "100%",
          aspectRatio: frame.ar,
          background: stripe + ", " + hexA(tint, 0.08),
          backgroundColor: "var(--paper2)",
          border: "1px solid var(--line)",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <div className="mono" style={{ fontSize: 12, color: "var(--ink-soft)", textAlign: "center", padding: 8 }}>
          ◳ {frame.file}<br />not on R2 yet
        </div>
      </div>
    );
  }

  return (
    <div
      style={{
        position: "relative",
        width: "100%",
        minHeight: loaded ? 0 : 80,
        aspectRatio: loaded ? "auto" : frame.ar,
        background: loaded ? "transparent" : stripe + ", " + hexA(tint, 0.08),
        backgroundColor: loaded ? "#1c1814" : "var(--paper2)",
        border: "1px solid var(--line)",
        overflow: "hidden",
        lineHeight: 0,
      }}
    >
      <img
        src={frame.url}
        alt={frame.caption || frame.file}
        loading="lazy"
        decoding="async"
        onLoad={() => setLoaded(true)}
        onError={() => setFailed(true)}
        style={{
          display: "block",
          width: "100%",
          height: "auto",
          opacity: loaded ? 1 : 0,
          transition: "opacity 0.45s ease",
        }}
      />
      {showCaption && loaded && (
        <div
          className="serif"
          style={{
            position: "absolute",
            bottom: 0,
            left: 0,
            right: 0,
            textAlign: "center",
            fontStyle: "italic",
            fontSize: big ? 14 : 12,
            color: "#f4e7d6",
            background: "linear-gradient(to top, rgba(20,16,13,0.7), transparent)",
            padding: "18px 8px 6px",
            lineHeight: 1.3,
          }}
        >
          {frame.caption}
        </div>
      )}
    </div>
  );
}

function Sprockets() {
  return (
    <div
      style={{
        position: "absolute",
        top: 0,
        bottom: 0,
        left: 0,
        width: 9,
        background:
          "repeating-linear-gradient(to bottom, transparent 0 6px, rgba(43,38,34,0.18) 6px 10px, transparent 10px 16px)",
        opacity: 0.5,
      }}
    />
  );
}

/* hex -> rgba */
function hexA(hex, a) {
  const h = hex.replace("#", "");
  const r = parseInt(h.substring(0, 2), 16);
  const g = parseInt(h.substring(2, 4), 16);
  const b = parseInt(h.substring(4, 6), 16);
  return `rgba(${r},${g},${b},${a})`;
}

/* ---------- Desktop icon ---------- */
function DesktopIcon({ icon, label, x, y, onOpen, accent }) {
  const [drag, setDrag] = useState({ x, y, moving: false });
  const ref = useRef(null);
  const start = useRef(null);

  const onDown = (e) => {
    const pt = e.touches ? e.touches[0] : e;
    start.current = { mx: pt.clientX, my: pt.clientY, ox: drag.x, oy: drag.y, moved: false };
    const move = (ev) => {
      const p = ev.touches ? ev.touches[0] : ev;
      const dx = p.clientX - start.current.mx;
      const dy = p.clientY - start.current.my;
      if (Math.abs(dx) > 3 || Math.abs(dy) > 3) start.current.moved = true;
      setDrag((d) => ({ ...d, x: start.current.ox + dx, y: start.current.oy + dy, moving: true }));
    };
    const up = () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
      window.removeEventListener("touchmove", move);
      window.removeEventListener("touchend", up);
      setDrag((d) => ({ ...d, moving: false }));
      if (!start.current.moved) {
        window.SFX && SFX.open();
        onOpen && onOpen();
      }
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
    window.addEventListener("touchmove", move, { passive: false });
    window.addEventListener("touchend", up);
  };

  return (
    <div
      ref={ref}
      data-clickable
      onMouseDown={onDown}
      onTouchStart={onDown}
      style={{
        position: "absolute",
        left: drag.x,
        top: drag.y,
        width: 78,
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        gap: 4,
        zIndex: drag.moving ? 50 : 2,
        userSelect: "none",
      }}
    >
      <div style={{ filter: "drop-shadow(2px 2px 0 rgba(43,38,34,0.25))" }}>{icon}</div>
      <div
        className="pixel"
        style={{
          fontSize: 8,
          textAlign: "center",
          background: accent || "var(--paper)",
          color: accent ? "#fff" : "var(--ink)",
          padding: "2px 4px 1px",
          border: "1px solid var(--line)",
          lineHeight: 1.4,
          textTransform: "uppercase",
        }}
      >
        {label}
      </div>
    </div>
  );
}

/* ---------- pixel SVG icons ---------- */
const IconFolder = ({ c = "#c9a44c" }) => (
  <svg width="46" height="40" viewBox="0 0 46 40" shapeRendering="crispEdges">
    <path d="M2 8 h14 l4 4 h22 v2 H2 Z" fill={c} stroke="#2b2622" strokeWidth="2" />
    <path d="M2 13 h42 v23 H2 Z" fill={c} stroke="#2b2622" strokeWidth="2" />
    <path d="M2 13 h42 v3 H2 Z" fill="rgba(255,255,255,0.35)" />
  </svg>
);
const IconFilm = () => (
  <svg width="44" height="44" viewBox="0 0 44 44" shapeRendering="crispEdges">
    <circle cx="22" cy="22" r="20" fill="#3a342e" stroke="#2b2622" strokeWidth="2" />
    <circle cx="22" cy="22" r="6" fill="#f4e7d6" stroke="#2b2622" strokeWidth="2" />
    {[0, 60, 120, 180, 240, 300].map((a) => {
      const r = (a * Math.PI) / 180;
      return (
        <circle
          key={a}
          cx={22 + Math.cos(r) * 13}
          cy={22 + Math.sin(r) * 13}
          r="2.5"
          fill="#f4e7d6"
        />
      );
    })}
    <rect x="20" y="0" width="10" height="8" fill="#c97b5a" stroke="#2b2622" strokeWidth="2" />
  </svg>
);
const IconTrash = () => (
  <svg width="34" height="42" viewBox="0 0 34 42" shapeRendering="crispEdges">
    <rect x="6" y="10" width="22" height="28" fill="#e9dcc6" stroke="#2b2622" strokeWidth="2" />
    {[12, 17, 22].map((x) => (
      <line key={x} x1={x} y1="14" x2={x} y2="34" stroke="#2b2622" strokeWidth="2" />
    ))}
    <rect x="3" y="5" width="28" height="6" fill="#e9dcc6" stroke="#2b2622" strokeWidth="2" />
    <rect x="13" y="1" width="8" height="5" fill="#e9dcc6" stroke="#2b2622" strokeWidth="2" />
  </svg>
);
const IconNote = () => (
  <svg width="42" height="44" viewBox="0 0 42 44" shapeRendering="crispEdges">
    <rect x="4" y="4" width="34" height="36" fill="#f3e07a" stroke="#2b2622" strokeWidth="2" />
    {[14, 20, 26, 32].map((y) => (
      <line key={y} x1="9" y1={y} x2="33" y2={y} stroke="rgba(43,38,34,0.4)" strokeWidth="1.5" />
    ))}
  </svg>
);
const IconCamera = () => (
  <svg width="46" height="38" viewBox="0 0 46 38" shapeRendering="crispEdges">
    <rect x="2" y="8" width="42" height="26" fill="#5d544c" stroke="#2b2622" strokeWidth="2" />
    <rect x="14" y="3" width="12" height="6" fill="#5d544c" stroke="#2b2622" strokeWidth="2" />
    <circle cx="23" cy="21" r="8" fill="#c9a44c" stroke="#2b2622" strokeWidth="2" />
    <circle cx="23" cy="21" r="3" fill="#2b2622" />
    <rect x="34" y="11" width="6" height="4" fill="#c97b5a" stroke="#2b2622" strokeWidth="1.5" />
  </svg>
);

Object.assign(window, {
  MacWindow,
  useDrag,
  PixelButton,
  PhotoPlaceholder,
  DesktopIcon,
  IconFolder,
  IconFilm,
  IconTrash,
  IconNote,
  IconCamera,
  hexA,
});
