import Image from "next/image";
import { resolveMedia } from "@/lib/media";
import { cn } from "@/lib/utils";
import { FabricPattern, type FabricKind } from "./FabricPattern";

export type SlotTone =
  | "cotton"
  | "indigo"
  | "thread"
  | "hiviz"
  | "melange"
  | "ember";

const TONES: Record<SlotTone, React.CSSProperties> = {
  cotton: {
    "--pattern-a": "#171C2B",
    "--pattern-b": "#20283C",
    "--pattern-c": "#0D1220",
    "--pattern-thread": "#F5F1E8",
    "--pattern-glow": "#E0A458",
    "--pattern-slub": "#F5F1E8",
  } as React.CSSProperties,
  indigo: {
    "--pattern-a": "#12193A",
    "--pattern-b": "#1B2A5B",
    "--pattern-c": "#070B1A",
    "--pattern-thread": "#93A7E8",
    "--pattern-glow": "#3A56A6",
    "--pattern-slub": "#F5F1E8",
  } as React.CSSProperties,
  thread: {
    "--pattern-a": "#1E1808",
    "--pattern-b": "#2E2410",
    "--pattern-c": "#0C0A05",
    "--pattern-thread": "#E0A458",
    "--pattern-glow": "#E0A458",
    "--pattern-slub": "#F5F1E8",
  } as React.CSSProperties,
  hiviz: {
    "--pattern-a": "#1A1B0C",
    "--pattern-b": "#262713",
    "--pattern-c": "#0B0C06",
    "--pattern-thread": "#D8E04A",
    "--pattern-glow": "#D8E04A",
    "--pattern-slub": "#F5F1E8",
  } as React.CSSProperties,
  melange: {
    "--pattern-a": "#1A1D24",
    "--pattern-b": "#272C36",
    "--pattern-c": "#101319",
    "--pattern-thread": "#8A8F9C",
    "--pattern-glow": "#8A8F9C",
    "--pattern-slub": "#F5F1E8",
  } as React.CSSProperties,
  // Warmer and more lit than `thread`, which is nearly black. Meant for the one
  // place on the site that is asking the reader to speak rather than to read.
  ember: {
    "--pattern-a": "#2E1F14",
    "--pattern-b": "#4A3220",
    "--pattern-c": "#17100A",
    "--pattern-thread": "#F0D3A8",
    "--pattern-glow": "#E0A458",
    "--pattern-slub": "#F5F1E8",
  } as React.CSSProperties,
};

const RATIOS: Record<string, string> = {
  "16/9": "56.25%",
  "4/3": "75%",
  "3/2": "66.666%",
  "1/1": "100%",
  "4/5": "125%",
  "3/4": "133.333%",
  "21/9": "42.857%",
};

export interface MediaSlotProps {
  /** Filename stem the client uses in /public/media to fill this slot. */
  id: string;
  /** Alt text used when a real photograph is present. */
  alt: string;
  ratio?: keyof typeof RATIOS;
  pattern?: FabricKind;
  tone?: SlotTone;
  /** Optional caption rendered over the artwork, useful on gallery cards. */
  caption?: string;
  className?: string;
  priority?: boolean;
  sizes?: string;
  fill?: boolean;
}

/**
 * An image position that is never empty.
 *
 * With no file present it renders generated fabric artwork. Drop
 * `public/media/<id>.jpg` and the photograph replaces it on the next build.
 */
export function MediaSlot({
  id,
  alt,
  ratio = "4/3",
  pattern = "weave",
  tone = "cotton",
  caption,
  className,
  priority = false,
  sizes = "(max-width: 768px) 100vw, 50vw",
  fill = false,
}: MediaSlotProps) {
  const src = resolveMedia(id);
  const seed = hash(id);

  return (
    <div
      data-slot={id}
      className={cn(
        "relative overflow-hidden bg-[var(--surface)] isolate",
        fill ? "absolute inset-0" : "w-full",
        className,
      )}
      style={fill ? undefined : { paddingBottom: RATIOS[ratio] }}
    >
      <div className="absolute inset-0">
        {src ? (
          <Image
            src={src}
            alt={alt}
            fill
            priority={priority}
            sizes={sizes}
            className="object-cover"
          />
        ) : (
          <>
            <FabricPattern
              kind={pattern}
              seed={seed}
              className="absolute inset-0 h-full w-full"
              // Tone tokens are consumed by the pattern gradients.
              style={TONES[tone]}
            />
            <span className="sr-only">{alt}</span>
          </>
        )}
      </div>

      {/* Keeps text legible whether the slot holds artwork or a real photo. */}
      <div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-[var(--ink)]/70 via-transparent to-transparent" />

      {caption ? (
        <p className="absolute inset-x-0 bottom-0 p-4 font-mono text-[11px] uppercase tracking-[0.18em] text-[var(--cotton)]/75">
          {caption}
        </p>
      ) : null}
    </div>
  );
}

function hash(value: string): number {
  let h = 2166136261;
  for (let i = 0; i < value.length; i++) {
    h ^= value.charCodeAt(i);
    h = Math.imul(h, 16777619);
  }
  return Math.abs(h % 9973) + 1;
}
