import { useEffect, useMemo, useState } from "react";
import { cn } from "../lib/utils";

const BAYER_4X4 = [
  [0, 8, 2, 10],
  [12, 4, 14, 6],
  [3, 11, 1, 9],
  [15, 7, 13, 5],
] as const;

interface CompanyPatternIconProps {
  companyName: string;
  logoUrl?: string | null;
  brandColor?: string | null;
  className?: string;
}

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

function mulberry32(seed: number): () => number {
  let state = seed >>> 0;
  return () => {
    state = (state + 0x6d2b79f5) >>> 0;
    let t = Math.imul(state ^ (state >>> 15), 1 | state);
    t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

function hslToRgb(h: number, s: number, l: number): [number, number, number] {
  const hue = ((h % 360) + 360) % 360;
  const sat = Math.max(0, Math.min(100, s)) / 100;
  const light = Math.max(0, Math.min(100, l)) / 100;

  const c = (1 - Math.abs(2 * light - 1)) * sat;
  const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));
  const m = light - c / 2;

  let r = 0;
  let g = 0;
  let b = 0;

  if (hue < 60) {
    r = c;
    g = x;
  } else if (hue < 120) {
    r = x;
    g = c;
  } else if (hue < 180) {
    g = c;
    b = x;
  } else if (hue < 240) {
    g = x;
    b = c;
  } else if (hue < 300) {
    r = x;
    b = c;
  } else {
    r = c;
    b = x;
  }

  return [
    Math.round((r + m) * 255),
    Math.round((g + m) * 255),
    Math.round((b + m) * 255),
  ];
}

function hexToHue(hex: string): number {
  const r = parseInt(hex.slice(1, 3), 16) / 255;
  const g = parseInt(hex.slice(3, 5), 16) / 255;
  const b = parseInt(hex.slice(5, 7), 16) / 255;
  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  const d = max - min;
  if (d === 0) return 0;
  let h = 0;
  if (max === r) h = ((g - b) / d) % 6;
  else if (max === g) h = (b - r) / d + 2;
  else h = (r - g) / d + 4;
  return ((h * 60) + 360) % 360;
}

function makeCompanyPatternDataUrl(seed: string, brandColor?: string | null, logicalSize = 22, cellSize = 2): string {
  if (typeof document === "undefined") return "";

  const canvas = document.createElement("canvas");
  canvas.width = logicalSize * cellSize;
  canvas.height = logicalSize * cellSize;

  const ctx = canvas.getContext("2d");
  if (!ctx) return "";

  const rand = mulberry32(hashString(seed));

  const hue = brandColor ? hexToHue(brandColor) : Math.floor(rand() * 360);
  const [offR, offG, offB] = hslToRgb(
    hue,
    54 + Math.floor(rand() * 14),
    36 + Math.floor(rand() * 12),
  );
  const [onR, onG, onB] = hslToRgb(
    hue + (rand() > 0.5 ? 10 : -10),
    86 + Math.floor(rand() * 10),
    82 + Math.floor(rand() * 10),
  );

  const center = (logicalSize - 1) / 2;
  const half = Math.max(center, 1);
  const gradientAngle = rand() * Math.PI * 2;
  const gradientDirX = Math.cos(gradientAngle);
  const gradientDirY = Math.sin(gradientAngle);
  const maxProjection = Math.abs(gradientDirX * half) + Math.abs(gradientDirY * half);
  const diagonalFrequency = 0.34 + rand() * 0.12;
  const antiDiagonalFrequency = 0.33 + rand() * 0.12;
  const diagonalPhase = rand() * Math.PI * 2;
  const antiDiagonalPhase = rand() * Math.PI * 2;

  ctx.fillStyle = `rgb(${offR} ${offG} ${offB})`;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  ctx.fillStyle = `rgb(${onR} ${onG} ${onB})`;
  const dotRadius = cellSize * 0.46;

  for (let y = 0; y < logicalSize; y++) {
    const dy = y - center;

    for (let x = 0; x < logicalSize; x++) {
      const dx = x - center;

      // Side-to-side signal where visible gradient is produced by dither density.
      const projection = dx * gradientDirX + dy * gradientDirY;
      const gradient = (projection / maxProjection + 1) * 0.5;
      const diagonal = Math.sin((dx + dy) * diagonalFrequency + diagonalPhase) * 0.5 + 0.5;
      const antiDiagonal = Math.sin((dx - dy) * antiDiagonalFrequency + antiDiagonalPhase) * 0.5 + 0.5;
      const hatch = diagonal * 0.5 + antiDiagonal * 0.5;
      const signal = Math.max(0, Math.min(1, gradient + (hatch - 0.5) * 0.22));

      // Canonical 16-level ordered dither: level 0..15 compared to Bayer 4x4 threshold index.
      const level = Math.max(0, Math.min(15, Math.floor(signal * 16)));
      const thresholdIndex = BAYER_4X4[y & 3]![x & 3]!;
      if (level <= thresholdIndex) continue;

      const cx = x * cellSize + cellSize / 2;
      const cy = y * cellSize + cellSize / 2;
      ctx.beginPath();
      ctx.arc(cx, cy, dotRadius, 0, Math.PI * 2);
      ctx.fill();
    }
  }

  return canvas.toDataURL("image/png");
}

export function CompanyPatternIcon({
  companyName,
  logoUrl,
  brandColor,
  className,
}: CompanyPatternIconProps) {
  const initial = companyName.trim().charAt(0).toUpperCase() || "?";
  const [imageError, setImageError] = useState(false);
  const logo = !imageError && typeof logoUrl === "string" && logoUrl.trim().length > 0 ? logoUrl : null;
  useEffect(() => {
    setImageError(false);
  }, [logoUrl]);
  const patternDataUrl = useMemo(
    () => makeCompanyPatternDataUrl(companyName.trim().toLowerCase(), brandColor),
    [companyName, brandColor],
  );

  return (
    <div
      className={cn(
        "relative flex items-center justify-center w-11 h-11 text-base font-semibold text-white overflow-hidden",
        className,
      )}
    >
      {logo ? (
        <img
          src={logo}
          alt={`${companyName} logo`}
          onError={() => setImageError(true)}
          className="absolute inset-0 h-full w-full object-cover"
        />
      ) : patternDataUrl ? (
        <img
          src={patternDataUrl}
          alt=""
          aria-hidden="true"
          className="absolute inset-0 h-full w-full"
          style={{ imageRendering: "pixelated" }}
        />
      ) : (
        <div className="absolute inset-0 bg-muted" />
      )}
      {!logo && (
        <span className="relative z-10 drop-shadow-[0_1px_2px_rgba(0,0,0,0.65)]">
          {initial}
        </span>
      )}
    </div>
  );
}
