import { seededRandom } from "@/lib/utils";

export type FabricKind = "weave" | "twill" | "knit" | "rib" | "jacquard" | "fleece";

/**
 * Generated fabric artwork.
 *
 * These are the default contents of every image slot on the site. They are real
 * structural drawings of the fabrics the mill actually runs, not placeholders,
 * so a page with no photography still looks deliberate.
 *
 * The SVG deliberately carries no viewBox. Cloth does not get bigger when you
 * look at more of it, so the structure tiles at a fixed size in CSS pixels and
 * a full bleed panel shows more repeats rather than larger ones.
 */
export function FabricPattern({
  kind,
  seed = 1,
  scale = 1.5,
  className,
  style,
}: {
  kind: FabricKind;
  seed?: number;
  /** Multiplies the repeat size. Larger reads bolder on big panels. */
  scale?: number;
  className?: string;
  style?: React.CSSProperties;
}) {
  const uid = `fp-${kind}-${seed}`;
  const size = structSize(kind) * scale;

  return (
    <svg
      className={className}
      style={style}
      width="100%"
      height="100%"
      aria-hidden="true"
      focusable="false"
    >
      <defs>
        <linearGradient id={`${uid}-wash`} x1="0" y1="0" x2="1" y2="1">
          <stop offset="0%" stopColor="var(--pattern-a)" />
          <stop offset="55%" stopColor="var(--pattern-b)" />
          <stop offset="100%" stopColor="var(--pattern-c)" />
        </linearGradient>

        {/* A single light falling across the cloth, not a wash over all of it. */}
        <radialGradient id={`${uid}-glow`} cx="26%" cy="14%" r="46%">
          <stop offset="0%" stopColor="var(--pattern-glow)" stopOpacity="0.16" />
          <stop offset="60%" stopColor="var(--pattern-glow)" stopOpacity="0.05" />
          <stop offset="100%" stopColor="var(--pattern-glow)" stopOpacity="0" />
        </radialGradient>

        <pattern
          id={`${uid}-struct`}
          width={size}
          height={size}
          patternUnits="userSpaceOnUse"
        >
          <g transform={`scale(${scale})`}>{structure(kind)}</g>
        </pattern>
      </defs>

      <rect width="100%" height="100%" fill={`url(#${uid}-wash)`} />
      <rect width="100%" height="100%" fill={`url(#${uid}-struct)`} opacity="0.4" />
      <rect width="100%" height="100%" fill={`url(#${uid}-glow)`} />
      <Slubs seed={seed} />
    </svg>
  );
}

function structSize(kind: FabricKind): number {
  switch (kind) {
    case "knit":
      return 14;
    case "rib":
      return 16;
    case "jacquard":
      return 40;
    case "fleece":
      return 24;
    case "twill":
      return 18;
    default:
      return 20;
  }
}

function structure(kind: FabricKind) {
  const line = {
    stroke: "var(--pattern-thread)",
    strokeWidth: 1.1,
    fill: "none",
    strokeLinecap: "round" as const,
  };

  switch (kind) {
    // Plain weave, one over one under.
    case "weave":
      return (
        <>
          <path d="M0 5 H20 M0 15 H20" {...line} />
          <path d="M5 0 V20 M15 0 V20" {...line} />
          <rect x="0" y="0" width="10" height="10" fill="var(--pattern-thread)" opacity="0.16" />
          <rect x="10" y="10" width="10" height="10" fill="var(--pattern-thread)" opacity="0.16" />
        </>
      );

    // Right hand twill, the denim structure. Denim runs Z twill, so the wale
    // climbs left to right. Three parallel runs spaced to tile seamlessly in
    // the 18 unit repeat, with a finer line between them for the 3 by 1 read.
    case "twill":
      return (
        <>
          <path
            d="M0 9 L9 0 M0 18 L18 0 M9 18 L18 9"
            {...line}
            strokeWidth={2.6}
          />
          <path
            d="M0 4.5 L4.5 0 M0 13.5 L13.5 0 M4.5 18 L18 4.5 M13.5 18 L18 13.5"
            {...line}
            strokeWidth={0.7}
            opacity={0.5}
          />
        </>
      );

    // Jersey face. The face of a single knit is columns of V shaped wales, one
    // per loop, which is what you actually see when you look at a t-shirt.
    case "knit":
      return (
        <>
          <path
            d="M0 0 L7 13 L14 0"
            {...line}
            strokeWidth={1.4}
            strokeLinejoin="round"
          />
          <path d="M0 -1 L7 12 L14 -1" {...line} strokeWidth={0.6} opacity={0.4} />
        </>
      );

    // One by one rib, vertical wales.
    case "rib":
      return (
        <>
          <path d="M4 0 V16 M12 0 V16" {...line} strokeWidth={2} />
          <path d="M8 0 V16" {...line} strokeWidth={0.7} opacity={0.45} />
        </>
      );

    // Mini jacquard diamond.
    case "jacquard":
      return (
        <>
          <path d="M20 4 L36 20 L20 36 L4 20 Z" {...line} />
          <path d="M20 12 L28 20 L20 28 L12 20 Z" {...line} opacity={0.6} />
          <circle cx="20" cy="20" r="1.6" fill="var(--pattern-thread)" opacity="0.7" />
        </>
      );

    // Brushed fleece, soft irregular pile.
    case "fleece":
      return (
        <>
          <path d="M2 20 C6 12, 10 26, 14 16 S22 22, 24 14" {...line} opacity={0.8} />
          <path d="M0 8 C5 2, 9 12, 14 4 S21 10, 24 3" {...line} opacity={0.5} />
        </>
      );
  }
}

/** Slub neps, the tiny irregularities that make cotton read as cotton. */
function Slubs({ seed }: { seed: number }) {
  const rand = seededRandom(seed * 7919 + 13);
  const marks = Array.from({ length: 30 }, () => ({
    x: rand() * 100,
    y: rand() * 100,
    r: 0.6 + rand() * 1.8,
    o: 0.05 + rand() * 0.18,
  }));

  return (
    <g fill="var(--pattern-slub)">
      {marks.map((m, i) => (
        <circle
          key={i}
          cx={`${m.x.toFixed(2)}%`}
          cy={`${m.y.toFixed(2)}%`}
          r={m.r.toFixed(2)}
          opacity={m.o.toFixed(3)}
        />
      ))}
    </g>
  );
}
