import { useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";

interface Point {
  x: number;
  y: number;
}

interface ZoneBBox {
  x: number;
  y: number;
  w: number;
  h: number;
  rotation?: number; // degrees, 0 / 90 / -90 / 180
}

interface Props {
  open: boolean;
  zoneId: number;
  zoneLabel: string;
  onConfirm: (points: Point[]) => void;
  onCancel: () => void;
}

const PADDING = 0.1;
const COMPOSITE_W = 827;
const COMPOSITE_H = 1209;
const SVG_NS = "http://www.w3.org/2000/svg";
const POINT_RADIUS = 18; // user-space units; visible on zoomed views

let bboxCache: Record<string, ZoneBBox> | null = null;

async function loadBBoxes(): Promise<Record<string, ZoneBBox>> {
  if (bboxCache) return bboxCache;
  const res = await fetch("/data/zone_bboxes.json");
  bboxCache = await res.json();
  return bboxCache!;
}

function paddedViewBox(b: ZoneBBox): string {
  const rotation = b.rotation ?? 0;
  const cx = b.x + b.w / 2;
  const cy = b.y + b.h / 2;
  let w = b.w;
  let h = b.h;
  if (rotation === 90 || rotation === -90) {
    w = b.h;
    h = b.w;
  }
  const padX = w * PADDING;
  const padY = h * PADDING;
  const minX = cx - w / 2 - padX;
  const minY = cy - h / 2 - padY;
  return `${minX} ${minY} ${w + 2 * padX} ${h + 2 * padY}`;
}

function rotationTransform(b: ZoneBBox): string | null {
  const rotation = b.rotation ?? 0;
  if (rotation === 0) return null;
  const cx = b.x + b.w / 2;
  const cy = b.y + b.h / 2;
  return `rotate(${rotation} ${cx} ${cy})`;
}

export function ZoneDetailView({ open, zoneId, zoneLabel, onConfirm, onCancel }: Props) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [svgText, setSvgText] = useState<string | null>(null);
  const [points, setPoints] = useState<Point[]>([]);

  // Load SVG + bboxes
  useEffect(() => {
    if (!open) return;
    setPoints([]);
    setSvgText(null);
    let cancelled = false;

    Promise.all([
      fetch("/scheme/exterior.svg").then((r) => r.text()),
      loadBBoxes(),
    ]).then(([text, bboxes]) => {
      if (cancelled) return;
      const b = bboxes[String(zoneId)];
      const finalVB = b ? paddedViewBox(b) : `0 0 ${COMPOSITE_W} ${COMPOSITE_H}`;
      const rotXform = b ? rotationTransform(b) : null;

      let mutated = text;
      mutated = mutated.replace(/<script[\s\S]*?<\/script>/gi, "");
      mutated = mutated.replace(/(<svg\b[^>]*?)\sviewBox\s*=\s*"[^"]*"/i, `$1 viewBox="${finalVB}"`);
      mutated = mutated.replace(
        /(<svg\b[^>]*?)\s(?:width|height)\s*=\s*"[^"]*"/gi,
        "$1"
      );
      mutated = mutated.replace(
        /<svg\b/i,
        `<svg width="100%" height="100%" preserveAspectRatio="xMidYMid meet"`
      );
      // Wrap inner content in rotated <g> so visible orientation is correct.
      // We always wrap (even with identity rotation) so the point-overlay <g>
      // append target is consistent.
      const openMatch = mutated.match(/<svg\b[^>]*?>/i);
      const closeIdx = mutated.lastIndexOf("</svg>");
      if (openMatch && closeIdx > -1) {
        const openEnd = (openMatch.index ?? 0) + openMatch[0].length;
        const before = mutated.slice(0, openEnd);
        const inner = mutated.slice(openEnd, closeIdx);
        const after = mutated.slice(closeIdx);
        const xform = rotXform ? ` transform="${rotXform}"` : "";
        mutated = `${before}<g data-rot="1"${xform}>${inner}</g>${after}`;
      }

      setSvgText(mutated);
    });
    return () => { cancelled = true; };
  }, [open, zoneId]);

  // After SVG mounts, apply fill highlights
  useEffect(() => {
    if (!svgText) return;
    const el = containerRef.current;
    if (!el) return;
    const svg = el.querySelector("svg") as SVGSVGElement | null;
    if (!svg) return;

    svg.querySelectorAll("path[class]").forEach((p) => {
      const cls = p.getAttribute("class") ?? "";
      if (cls === String(zoneId)) {
        p.setAttribute("fill", "rgba(239, 68, 68, 0.18)");
        p.setAttribute("stroke", "rgb(239, 68, 68)");
        p.setAttribute("stroke-width", "2");
      } else {
        p.setAttribute("fill", "rgba(0,0,0,0.04)");
        p.setAttribute("stroke", "rgba(0,0,0,0.25)");
      }
      (p as SVGElement).style.pointerEvents = "none";
    });
    svg.querySelectorAll("path:not([class])").forEach((p) => {
      (p as SVGElement).style.opacity = "0.4";
      (p as SVGElement).style.pointerEvents = "none";
    });
  }, [svgText, zoneId]);

  // Imperatively render points as SVG circles inside the rotated <g>.
  // This guarantees they sit at the exact same place as the SVG content,
  // regardless of letterboxing / aspect-ratio.
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const svg = el.querySelector("svg") as SVGSVGElement | null;
    if (!svg) return;
    const rotGroup = svg.querySelector("g[data-rot]") as SVGGElement | null;
    if (!rotGroup) return;

    // Remove existing overlay group if any
    const existing = rotGroup.querySelector("g[data-points]");
    if (existing) existing.remove();

    // Build new overlay group
    const group = document.createElementNS(SVG_NS, "g");
    group.setAttribute("data-points", "1");

    points.forEach((p, i) => {
      const cx = p.x * COMPOSITE_W;
      const cy = p.y * COMPOSITE_H;
      const circle = document.createElementNS(SVG_NS, "circle");
      circle.setAttribute("cx", String(cx));
      circle.setAttribute("cy", String(cy));
      circle.setAttribute("r", String(POINT_RADIUS));
      circle.setAttribute("fill", "rgb(239, 68, 68)");
      circle.setAttribute("stroke", "white");
      circle.setAttribute("stroke-width", "3");
      circle.setAttribute("data-point-index", String(i));
      (circle as SVGElement).style.cursor = "pointer";
      group.appendChild(circle);

      const text = document.createElementNS(SVG_NS, "text");
      text.setAttribute("x", String(cx));
      text.setAttribute("y", String(cy));
      text.setAttribute("text-anchor", "middle");
      text.setAttribute("dominant-baseline", "central");
      text.setAttribute("fill", "white");
      text.setAttribute("font-size", "20");
      text.setAttribute("font-weight", "bold");
      text.setAttribute("data-point-label", String(i));
      (text as SVGElement).style.pointerEvents = "none";
      (text as SVGElement).style.userSelect = "none";
      text.textContent = String(i + 1);
      group.appendChild(text);
    });

    rotGroup.appendChild(group);
  }, [svgText, points]);

  function handleTap(e: React.MouseEvent<HTMLDivElement>) {
    // If user clicked an existing point circle, remove it (if it's the last one)
    const target = e.target as Element;
    const pointIdxAttr = target.getAttribute?.("data-point-index");
    if (pointIdxAttr != null) {
      const idx = Number(pointIdxAttr);
      if (idx === points.length - 1) {
        setPoints((p) => p.slice(0, -1));
      }
      return;
    }

    const el = containerRef.current;
    if (!el) return;
    const svg = el.querySelector("svg") as SVGSVGElement | null;
    if (!svg) return;

    // getScreenCTM gives matrix from SVG root user-space to screen pixels.
    // It does NOT include inner <g> transforms — so svgPt is in the rotated viewBox frame.
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const ctm = svg.getScreenCTM();
    if (!ctm) return;
    const svgPt = pt.matrixTransform(ctm.inverse());

    // Convert from the visible (rotated) frame back to the original composite frame
    // so storage is in a canonical coord system.
    const bboxes = bboxCache;
    const b = bboxes?.[String(zoneId)] ?? null;
    const original = b
      ? inverseRotateAroundBboxCenter({ x: svgPt.x, y: svgPt.y }, b)
      : { x: svgPt.x, y: svgPt.y };

    const xN = Math.max(0, Math.min(1, original.x / COMPOSITE_W));
    const yN = Math.max(0, Math.min(1, original.y / COMPOSITE_H));
    setPoints((prev) => [...prev, { x: xN, y: yN }]);
  }

  if (!open) return null;

  return (
    <div className="fixed inset-0 z-50 bg-background flex flex-col">
      <header className="flex items-center justify-between p-4 border-b">
        <div>
          <div className="text-xs text-muted-foreground">Зона</div>
          <h2 className="text-lg font-semibold capitalize">{zoneLabel}</h2>
        </div>
        <div className="text-xs text-muted-foreground">
          Точек: <span className="font-semibold text-foreground">{points.length}</span>
        </div>
      </header>

      <main className="flex-1 overflow-hidden relative bg-card">
        <div
          ref={containerRef}
          onClick={handleTap}
          className="w-full h-full"
          style={{ touchAction: "manipulation" }}
          dangerouslySetInnerHTML={svgText ? { __html: svgText } : undefined}
        />
        {!svgText && (
          <div className="absolute inset-0 flex items-center justify-center text-sm text-muted-foreground pointer-events-none">
            Загружаю схему…
          </div>
        )}
      </main>

      <footer className="border-t p-3 flex items-center gap-3 bg-card">
        <button
          onClick={onCancel}
          className="flex-1 flex items-center justify-center gap-2 py-3 rounded-lg border border-destructive text-destructive hover:bg-destructive/10 active:bg-destructive/20 transition-colors font-semibold"
          aria-label="Отмена"
        >
          <span className="text-2xl leading-none">&#x2715;</span>
          <span>Отмена</span>
        </button>
        <button
          onClick={() => onConfirm(points)}
          disabled={points.length === 0}
          className={cn(
            "flex-1 flex items-center justify-center gap-2 py-3 rounded-lg font-semibold transition-colors",
            points.length === 0
              ? "bg-muted text-muted-foreground"
              : "bg-primary text-primary-foreground hover:opacity-90 active:opacity-80"
          )}
          aria-label="Готово"
        >
          <span className="text-2xl leading-none">&#x2713;</span>
          <span>Готово ({points.length})</span>
        </button>
      </footer>
    </div>
  );
}

/** Convert tap point from rotated/visible viewBox frame back to original composite frame. */
function inverseRotateAroundBboxCenter(
  pt: { x: number; y: number },
  b: ZoneBBox
): { x: number; y: number } {
  const rot = b.rotation ?? 0;
  if (rot === 0) return pt;
  const cx = b.x + b.w / 2;
  const cy = b.y + b.h / 2;
  const dx = pt.x - cx;
  const dy = pt.y - cy;
  const rad = (-rot * Math.PI) / 180;
  const cos = Math.cos(rad);
  const sin = Math.sin(rad);
  return {
    x: cx + dx * cos - dy * sin,
    y: cy + dx * sin + dy * cos,
  };
}
