"use client";

import { useCallback, useRef, useState } from "react";
import { FabricPattern } from "@/components/media/FabricPattern";

/**
 * Raw against finished.
 *
 * A draggable wipe between rigid denim and the same cloth after the laundry and
 * the laser. Keyboard operable via the slider, because the whole point of the
 * section is the comparison and it should not be mouse only.
 */
export function WashWipe({
  beforeLabel = "Rigid, off the loom",
  afterLabel = "Laser and laundry finished",
  beforeSrc = null,
  afterSrc = null,
  beforeAlt = "Rigid indigo denim before finishing",
  afterAlt = "The same denim after laser whiskering and laundry",
}: {
  beforeLabel?: string;
  afterLabel?: string;
  /** Resolved on the server by the page, so /public/media stays drop in. */
  beforeSrc?: string | null;
  afterSrc?: string | null;
  beforeAlt?: string;
  afterAlt?: string;
}) {
  const [value, setValue] = useState(52);
  const frame = useRef<HTMLDivElement>(null);
  const dragging = useRef(false);

  const setFromClientX = useCallback((clientX: number) => {
    const node = frame.current;
    if (!node) return;
    const rect = node.getBoundingClientRect();
    const pct = ((clientX - rect.left) / rect.width) * 100;
    setValue(Math.min(100, Math.max(0, pct)));
  }, []);

  return (
    <div
      ref={frame}
      className="relative aspect-[16/10] w-full select-none overflow-hidden border border-[var(--rule)]"
      onPointerDown={(e) => {
        dragging.current = true;
        e.currentTarget.setPointerCapture(e.pointerId);
        setFromClientX(e.clientX);
      }}
      onPointerMove={(e) => {
        if (dragging.current) setFromClientX(e.clientX);
      }}
      onPointerUp={(e) => {
        dragging.current = false;
        e.currentTarget.releasePointerCapture(e.pointerId);
      }}
    >
      {/* After, the full width base layer. */}
      <Layer
        src={afterSrc}
        alt={afterAlt}
        kind="twill"
        tone={{
          "--pattern-a": "#3d4b78",
          "--pattern-b": "#5a6a9c",
          "--pattern-c": "#2a3559",
          "--pattern-thread": "#dfe4f5",
          "--pattern-glow": "#f5f1e8",
          "--pattern-slub": "#ffffff",
        }}
      />

      {/* Before, clipped to the wipe. */}
      <div
        className="absolute inset-0"
        style={{ clipPath: `inset(0 ${100 - value}% 0 0)` }}
      >
        <Layer
          src={beforeSrc}
          alt={beforeAlt}
          kind="twill"
          tone={{
            "--pattern-a": "#0b1130",
            "--pattern-b": "#16205199",
            "--pattern-c": "#05081a",
            "--pattern-thread": "#3a56a6",
            "--pattern-glow": "#1b2a5b",
            "--pattern-slub": "#93a7e8",
          }}
        />
      </div>

      {/* The wipe itself. */}
      <div
        className="pointer-events-none absolute inset-y-0 w-px bg-[var(--thread)]"
        style={{ left: `${value}%` }}
      >
        <span className="absolute top-1/2 left-1/2 flex h-10 w-10 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-[var(--thread)] bg-[var(--ink)]/85 font-mono text-[10px] text-[var(--thread)] backdrop-blur-sm">
          &lt;&gt;
        </span>
      </div>

      {/* One row rather than two independently pinned corners. Anchored apart,
          the two labels grow toward each other as the frame narrows and collide
          on a phone. A flex row reserves the space instead, so they wrap. */}
      <div className="pointer-events-none absolute inset-x-0 bottom-0 flex items-end justify-between gap-4 p-4">
        <p className="max-w-[45%] font-mono text-[10px] leading-snug tracking-[0.12em] uppercase text-[var(--cotton)]/80 sm:tracking-[0.18em]">
          {beforeLabel}
        </p>
        <p className="max-w-[45%] text-right font-mono text-[10px] leading-snug tracking-[0.12em] uppercase text-[var(--cotton)]/80 sm:tracking-[0.18em]">
          {afterLabel}
        </p>
      </div>

      {/* The accessible control. Visually minimal, fully operable. */}
      <label className="absolute inset-x-0 top-0 flex items-center gap-3 p-4">
        <span className="sr-only">
          Reveal how much of the rigid denim is shown against the finished denim
        </span>
        <input
          type="range"
          min={0}
          max={100}
          value={Math.round(value)}
          onChange={(e) => setValue(Number(e.target.value))}
          className="h-1 w-full cursor-ew-resize appearance-none rounded-full bg-[var(--cotton)]/15 accent-[var(--thread)]"
        />
      </label>
    </div>
  );
}

function Layer({
  src,
  alt,
  kind,
  tone,
}: {
  src: string | null;
  alt: string;
  kind: "twill";
  tone: Record<string, string>;
}) {
  if (src) {
    return (
      // A plain img keeps the two layers pixel aligned inside the clip path,
      // which next/image's wrapper makes awkward.
      // eslint-disable-next-line @next/next/no-img-element
      <img src={src} alt={alt} className="absolute inset-0 h-full w-full object-cover" />
    );
  }

  return (
    <>
      <FabricPattern
        kind={kind}
        seed={alt.length * 131}
        className="absolute inset-0 h-full w-full"
        style={tone as React.CSSProperties}
      />
      <span className="sr-only">{alt}</span>
    </>
  );
}
