"use client";

import { ZoomIn, ZoomOut } from "lucide-react";
import { useId, useMemo, useState } from "react";
import { Slider } from "@/components/ui/slider";
import { iconFor } from "@/app/lib/factorio-data";
import { localizedName } from "@/app/lib/i18n";
import type { BeaconLayoutResult, Locale, Machine, TilePlacement } from "@/app/lib/types";
import { isBelt, isPipe, OPPOSITE, previewBounds, previewGeometry, VECTORS, type Direction } from "./preview-geometry";

const ANGLE = { north: 0, east: 90, south: 180, west: 270 };
const edge = (direction: Direction) => {
  const [dx, dy] = VECTORS[direction];
  return `${0.5 + dx / 2} ${0.5 + dy / 2}`;
};
function beltColor(id = "") {
  return id.startsWith("turbo") ? "#79c863" : id.startsWith("express") ? "#53bade" : id.startsWith("fast") ? "#e17765" : "#dfb448";
}
function fluidColor(id = "") {
  return ({ water: "#67bcec", "crude-oil": "#b5a4c7", "heavy-oil": "#e3a756", "light-oil": "#f3d770", "petroleum-gas": "#c58bbd" } as Record<string, string>)[id] ?? "#77d2ca";
}

export function BlueprintPreview({ layout, machine, locale, title, subtitle, grid }: {
  layout: BeaconLayoutResult; machine: Machine; locale: Locale; title: string; subtitle?: string; grid: { x: number; y: number };
}) {
  const [zoom, setZoom] = useState(100);
  const id = useId().replaceAll(":", "");
  const bounds = previewBounds(layout.bounds);
  const geometry = useMemo(() => previewGeometry(layout.placements), [layout.placements]);
  const tile = 18 * zoom / 100;
  const labels = locale === "de"
    ? { symbols: "Symbolansicht · 1 Quadrat = 1 Tile", zoom: "Vorschau-Zoom" }
    : { symbols: "Symbol view · 1 square = 1 tile", zoom: "Preview zoom" };

  function entity(placement: TilePlacement, index: number) {
    const direction = placement.direction ?? "north";
    const entityId = placement.entityId ?? machine.id;
    const count = layout.counts[placement.machineIndex ?? index];
    const productName = placement.productId ? localizedName(placement.productId, locale, placement.productType) : "";
    const name = placement.kind === "link" ? productName : localizedName(entityId, locale, "entity");
    let body;
    if (placement.kind === "link") {
      body = <>
        <rect width={placement.width} height={placement.height} fill="#13232b" rx={0.12} />
        <image href={iconFor(placement.productId ?? entityId, placement.productType)} x={0.06} y={0.06} width={0.88} height={0.88} preserveAspectRatio="xMidYMid meet" />
        <text x={1.12} y={0.75} fontSize={0.7} fontWeight={600} fill={placement.flowDirection === "input" ? "#a1d394" : "#f2c575"}>
          {placement.flowDirection === "input" ? "In" : "Out"}
        </text>
      </>;
    } else if (isBelt(placement)) {
      const incoming = geometry.connections(placement);
      const entrances = placement.beltEnd === "output" ? [] : incoming.length ? incoming : [OPPOSITE[direction]];
      const outgoing = placement.beltEnd === "input" ? "0.5 0.5" : edge(direction);
      const paths = entrances.length ? entrances.map((from) => `M ${edge(from)} Q 0.5 0.5 ${outgoing}`) : [`M 0.5 0.5 L ${outgoing}`];
      body = <>
        {paths.map((d, i) => <g key={i}>
          <path d={d} fill="none" stroke="#353634" strokeWidth={0.92} />
          <path d={d} fill="none" stroke={beltColor(entityId)} strokeWidth={0.65} />
          <path d={d} fill="none" stroke="#29271c" strokeWidth={0.045} />
        </g>)}
        <g transform={`rotate(${ANGLE[direction]} 0.5 0.5)`}>
          {placement.beltEnd ? <rect x={0.06} y={0.27} width={0.88} height={0.4} rx={0.05} fill="#333940" stroke={beltColor(entityId)} strokeWidth={0.07} /> :
            <path d="M .27 .54 L .5 .35 L .73 .54" fill="none" stroke="#25251e" strokeWidth={0.07} />}
        </g>
      </>;
    } else if (isPipe(placement)) {
      const ports = geometry.connections(placement);
      if (placement.entityId === "pipe-to-ground" && !ports.includes(direction)) ports.push(direction);
      body = <>
        {ports.map((port) => <g key={port}>
          <path d={`M .5 .5 L ${edge(port)}`} stroke="#3c464e" strokeWidth={0.5} />
          <path d={`M .5 .5 L ${edge(port)}`} stroke={fluidColor(placement.label)} strokeWidth={0.23} />
        </g>)}
        {placement.entityId === "pipe-to-ground"
          ? <rect x={0.2} y={0.2} width={0.6} height={0.6} rx={0.1} fill="#303d45" stroke={fluidColor(placement.label)} strokeWidth={0.09} />
          : <circle cx={0.5} cy={0.5} r={0.19} fill={fluidColor(placement.label)} />}
      </>;
    } else if (entityId.endsWith("inserter")) {
      // A top-down arm at the pickup end, inside its one-tile footprint.
      const color = entityId === "fast-inserter" ? "#55b5ed" : entityId === "bulk-inserter" ? "#8fc96c" : entityId === "stack-inserter" ? "#e9e7d9" : "#e7b84c";
      body = <g transform={`rotate(${ANGLE[direction]} .5 .5)`}>
        <rect x={0.23} y={0.4} width={0.54} height={0.43} rx={0.05} fill="#393f43" stroke={color} strokeWidth={0.07} />
        <path d="M .5 .62 L .38 .39 L .5 .14 M .36 .12 L .36 .22 L .64 .22 L .64 .12" fill="none" stroke={color} strokeWidth={0.095} strokeLinejoin="round" />
        <circle cx={0.5} cy={0.62} r={0.09} fill={color} />
      </g>;
    } else {
      const size = Math.min(placement.width, placement.height);
      const productSize = Math.min(size * 0.48, 1.6);
      const productX = (placement.width - productSize) / 2;
      const productY = (placement.height - productSize) / 2;
      const inset = 0.12;
      body = <>
        <rect x={0.045} y={0.045} width={placement.width - 0.09} height={placement.height - 0.09} fill={placement.kind === "machine" ? "#a0751d18" : "#69c5df0d"} stroke={placement.kind === "machine" ? "#d0a95a88" : "#69c5df55"} strokeWidth={0.055} />
        <image href={iconFor(entityId)} x={(placement.width - size) / 2 + inset} y={(placement.height - size) / 2 + inset} width={size - inset * 2} height={size - inset * 2} preserveAspectRatio="xMidYMid meet" />
        {placement.kind === "machine" && placement.productId ? <g>
          <rect x={productX - 0.08} y={productY - 0.08} width={productSize + 0.16} height={productSize + 0.16} rx={0.16} fill="#0a1016" fillOpacity={0.9} stroke="#e7c987" strokeOpacity={0.65} strokeWidth={0.045} />
          <image href={iconFor(placement.productId, placement.productType)} x={productX} y={productY} width={productSize} height={productSize} preserveAspectRatio="xMidYMid meet" />
        </g> : null}
        {placement.kind === "machine" && count !== undefined && count > 0 ? <>
          <rect x={placement.width - 0.82} y={0.12} width={0.7} height={0.7} rx={0.12} fill="#101619" />
          <text x={placement.width - 0.47} y={0.64} textAnchor="middle" fill="#f5d49c" fontSize={0.5}>{count}</text>
        </> : null}
      </>;
    }
    return <g key={index} transform={`translate(${placement.x} ${placement.y})`}>
      <title>{name}{placement.kind === "machine" && productName ? ` · ${productName}` : ""}{placement.flowDirection ? ` · ${placement.flowDirection === "input" ? "In" : "Out"}` : ""}{placement.label ? ` · ${placement.label}` : ""}</title>
      <svg width={placement.width} height={placement.height} viewBox={`0 0 ${placement.width} ${placement.height}`} overflow="hidden">{body}</svg>
    </g>;
  }

  return <div className="blueprint-preview rounded-xl border-2 border-[#69c5df]/25 bg-[#0a0c0d] p-3">
    <div className="mb-3 flex flex-wrap items-center justify-between gap-3">
      <div className="min-w-0">
        <p className="text-sm font-medium text-zinc-100">{title}</p>
        <p className="mt-1 max-w-3xl text-xs leading-relaxed text-zinc-400">{subtitle}</p>
      </div>
      <div className="flex flex-wrap items-center gap-3">
        <span className="rounded-md border border-[#69c5df]/25 px-2 py-1 text-xs text-[#b7dbe8]">{labels.symbols}</span>
        <div className="flex items-center gap-2">
          <ZoomOut className="size-4 text-zinc-400" />
          <Slider aria-label={labels.zoom} value={[zoom]} min={40} max={300} step={10} onValueChange={(value) => setZoom(value[0])} className="w-28" />
          <ZoomIn className="size-4 text-zinc-400" />
          <span className="w-10 font-mono text-xs text-zinc-400">{zoom}%</span>
        </div>
      </div>
    </div>
    <div className="max-h-[620px] overflow-auto rounded-lg border border-white/10 bg-[#080b0d]">
      <svg role="img" aria-label={title} width={bounds.width * tile} height={bounds.height * tile} viewBox={`${bounds.x} ${bounds.y} ${bounds.width} ${bounds.height}`} style={{ display: "block", maxWidth: "none" }}>
        <defs>
          <pattern id={`${id}-tiles`} width={1} height={1} patternUnits="userSpaceOnUse">
            <path d="M 0 1 L 0 0 L 1 0" fill="none" stroke="#abb8c2" strokeOpacity={0.12} strokeWidth={0.045} />
          </pattern>
        </defs>
        <rect x={bounds.x} y={bounds.y} width={bounds.width} height={bounds.height} fill={`url(#${id}-tiles)`} />
        <rect x={0} y={0} width={grid.x} height={grid.y} fill="none" stroke="#69c5df" strokeOpacity={0.5} strokeWidth={0.08} strokeDasharray=".4 .4" />
        {geometry.power.map(({ from, to }, index) => <line key={`power-${index}`} x1={from.x + 1} y1={from.y + 1} x2={to.x + 1} y2={to.y + 1} stroke="#c89355" strokeOpacity={0.45} strokeWidth={0.065} />)}
        {geometry.tunnels.map(({ from, to }, index) => <line key={index} x1={from.x + 0.5} y1={from.y + 0.5} x2={to.x + 0.5} y2={to.y + 0.5} stroke={isPipe(from) ? fluidColor(from.label) : beltColor(from.entityId)} strokeOpacity={0.35} strokeWidth={0.13} strokeDasharray=".2 .25" />)}
        {layout.placements.map(entity)}
      </svg>
    </div>
  </div>;
}
