"use client";

// Sonuç sayfasının kahraman öğesi: 24 tercihin Türkiye haritası üzerinde
// risk renkli pinlerle gösterimi. Ülke seviyesinde il başına tek toplu pin;
// ile tıklayınca viewBox o ilin sınırlarına animasyonla akar, il büyür ve
// üniversite pinleri gerçek kampüs konumlarında adlarıyla görünür.
// Kilitli (paketsiz) tercihler il merkezinde adsız "?" pini olarak çizilir —
// üniversite adı client'a hiç inmediği için paywall haritadan delinemez.

import {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { ArrowLeft, Lock } from "lucide-react";
import { cities } from "turkey-map-react/lib/data";
import { Button } from "@/components/ui/button";
import {
  HARITA_GENISLIK,
  HARITA_UST_KIRPMA,
  HARITA_YUKSEKLIK,
  normalizeIlAdi,
} from "@/lib/harita";
import type { RiskSeviyesi } from "@/lib/risk";

export type HaritaPin = {
  /** Üniversite bazlı benzersiz anahtar (kilitlilerde sentetik) */
  id: string;
  /** Görünen ad — kilitli pinlerde boş bırakılır */
  universite: string;
  /** DB biçiminde il adı (büyük harf); harita dışıysa null */
  il: string | null;
  x: number;
  y: number;
  /** Bu üniversitedeki tercihlerin liste sıraları (1-24) */
  tercihSiralari: number[];
  risk: RiskSeviyesi;
  kilitli?: boolean;
};

const RISK_RENK: Record<RiskSeviyesi, string> = {
  guvenli: "oklch(0.696 0.17 162.5)", // emerald-500
  "az-riskli": "oklch(0.769 0.188 70.1)", // amber-500
  riskli: "oklch(0.637 0.237 25.3)", // red-500
};

const TAM_GORUNUM = {
  x: 0,
  y: HARITA_UST_KIRPMA,
  w: HARITA_GENISLIK,
  h: HARITA_YUKSEKLIK - HARITA_UST_KIRPMA,
};

type ViewBox = typeof TAM_GORUNUM;

/** "ORTA DOĞU TEKNİK ÜNİVERSİTESİ" → "Orta Doğu Teknik" */
function kisaUniAdi(ad: string): string {
  const kisa = ad
    .replace(/\s+(ÜNİVERSİTESİ|ENSTİTÜSÜ|MESLEK YÜKSEKOKULU)$/i, "")
    .trim();
  return kisa
    .toLocaleLowerCase("tr-TR")
    .split(" ")
    .map((k) =>
      k.length > 2 || k === "29"
        ? k.charAt(0).toLocaleUpperCase("tr-TR") + k.slice(1)
        : k,
    )
    .join(" ");
}

/** İldeki pinlerin çoğunluk riski (eşitlikte güvenli taraf). */
function baskinRisk(pinler: HaritaPin[]): RiskSeviyesi {
  const sayac: Record<RiskSeviyesi, number> = {
    guvenli: 0,
    "az-riskli": 0,
    riskli: 0,
  };
  for (const p of pinler) sayac[p.risk] += p.tercihSiralari.length;
  return (["guvenli", "az-riskli", "riskli"] as const).reduce((a, b) =>
    sayac[b] > sayac[a] ? b : a,
  );
}

/** Aynı noktaya düşen pinleri küçük bir halka üzerinde ayrıştırır. */
function cakismaAc(pinler: HaritaPin[]): HaritaPin[] {
  const gruplar = new Map<string, HaritaPin[]>();
  for (const p of pinler) {
    const key = `${Math.round(p.x)}:${Math.round(p.y)}`;
    const grup = gruplar.get(key);
    if (grup) grup.push(p);
    else gruplar.set(key, [p]);
  }
  const sonuc: HaritaPin[] = [];
  for (const grup of gruplar.values()) {
    if (grup.length === 1) {
      sonuc.push(grup[0]);
      continue;
    }
    grup.forEach((p, i) => {
      const aci = (2 * Math.PI * i) / grup.length;
      sonuc.push({ ...p, x: p.x + Math.cos(aci) * 5, y: p.y + Math.sin(aci) * 5 });
    });
  }
  return sonuc;
}

export function TercihHaritasi({
  pinler,
  seciliIl,
  onSeciliIlDegisti,
  onTercihSec,
}: {
  pinler: HaritaPin[];
  /** Zoom'lanacak il (DB biçimi) — liste tarafından da kontrol edilebilir */
  seciliIl: string | null;
  onSeciliIlDegisti: (il: string | null) => void;
  /** Alt şeritte bir tercihe dokunulunca (liste satırına in) */
  onTercihSec?: (sira: number) => void;
}) {
  const pathRefs = useRef(new Map<string, SVGPathElement>());
  const [vb, setVb] = useState<ViewBox>(TAM_GORUNUM);
  const vbRef = useRef<ViewBox>(TAM_GORUNUM);
  const animRef = useRef(0);

  const animateTo = useCallback((hedef: ViewBox) => {
    cancelAnimationFrame(animRef.current);
    const kaynak = { ...vbRef.current };
    const t0 = performance.now();
    const SURE = 380;
    const ease = (t: number) => 1 - Math.pow(1 - t, 3);
    const adim = (now: number) => {
      const t = Math.min(1, (now - t0) / SURE);
      const k = ease(t);
      const sonraki = {
        x: kaynak.x + (hedef.x - kaynak.x) * k,
        y: kaynak.y + (hedef.y - kaynak.y) * k,
        w: kaynak.w + (hedef.w - kaynak.w) * k,
        h: kaynak.h + (hedef.h - kaynak.h) * k,
      };
      vbRef.current = sonraki;
      setVb(sonraki);
      if (t < 1) animRef.current = requestAnimationFrame(adim);
    };
    animRef.current = requestAnimationFrame(adim);
  }, []);

  useEffect(() => () => cancelAnimationFrame(animRef.current), []);

  // seciliIl değişince ilgili ilin bbox'ına (veya tam görünüme) ak
  useEffect(() => {
    if (!seciliIl) {
      animateTo(TAM_GORUNUM);
      return;
    }
    const path = pathRefs.current.get(seciliIl);
    if (!path) return;
    const b = path.getBBox();
    const pad = Math.max(b.width, b.height) * 0.22;
    let x = b.x - pad;
    let y = b.y - pad;
    let w = b.width + pad * 2;
    let h = b.height + pad * 2;
    // viewBox oranını koru ki il yamulmadan büyüsün ve harita yüksekliği
    // zoom'da değişmesin (tam görünümle aynı oran)
    const oran = TAM_GORUNUM.w / TAM_GORUNUM.h;
    if (w / h > oran) {
      const yeniH = w / oran;
      y -= (yeniH - h) / 2;
      h = yeniH;
    } else {
      const yeniW = h * oran;
      x -= (yeniW - w) / 2;
      w = yeniW;
    }
    animateTo({ x, y, w, h });
  }, [seciliIl, animateTo]);

  const ilPinleri = useMemo(() => {
    const gruplar = new Map<string, HaritaPin[]>();
    for (const p of pinler) {
      if (!p.il) continue;
      const grup = gruplar.get(p.il);
      if (grup) grup.push(p);
      else gruplar.set(p.il, [p]);
    }
    return gruplar;
  }, [pinler]);

  // Ekran boyutu sabit kalsın diye SVG içi ölçüler zoom oranıyla çarpılır
  const sf = vb.w / HARITA_GENISLIK;
  const zoomda = Boolean(seciliIl);
  const seciliPinler = seciliIl ? (ilPinleri.get(seciliIl) ?? []) : [];
  const acikPinler = cakismaAc(seciliPinler);

  return (
    <div>
      <div className="relative">
        <svg
          viewBox={`${vb.x} ${vb.y} ${vb.w} ${vb.h}`}
          className="h-auto w-full"
          role="img"
          aria-label="Tercih listesinin Türkiye haritasındaki dağılımı"
        >
          {/* İl zeminleri */}
          {cities.map((city) => {
            const key = normalizeIlAdi(city.name);
            const iceriyor = ilPinleri.has(key);
            const secili = key === seciliIl;
            return (
              <path
                key={city.id}
                ref={(el) => {
                  if (el) pathRefs.current.set(key, el);
                  else pathRefs.current.delete(key);
                }}
                d={city.path}
                className={
                  iceriyor
                    ? "cursor-pointer transition-opacity duration-200 hover:opacity-80"
                    : undefined
                }
                fill={
                  secili
                    ? "oklch(0.97 0.014 254.6)" // blue-50: seçili zemin
                    : iceriyor
                      ? "oklch(0.882 0.059 254.1)" // blue-200
                      : "oklch(0.929 0.013 255.5)" // slate-200
                }
                stroke="white"
                strokeWidth={secili ? 1.6 * sf : 1 * sf}
                onClick={() => {
                  if (secili) onSeciliIlDegisti(null);
                  else if (iceriyor) onSeciliIlDegisti(key);
                }}
              >
                <title>
                  {iceriyor
                    ? `${city.name}: ${(ilPinleri.get(key) ?? []).reduce(
                        (a, p) => a + p.tercihSiralari.length,
                        0,
                      )} tercih — yakınlaşmak için tıkla`
                    : city.name}
                </title>
              </path>
            );
          })}

          {/* Ülke seviyesi: il başına toplu pin */}
          {!zoomda
            ? [...ilPinleri.entries()].map(([il, iller]) => {
                const adet = iller.reduce(
                  (a, p) => a + p.tercihSiralari.length,
                  0,
                );
                const cx =
                  iller.reduce((a, p) => a + p.x, 0) / iller.length;
                const cy =
                  iller.reduce((a, p) => a + p.y, 0) / iller.length;
                const renk = RISK_RENK[baskinRisk(iller)];
                return (
                  <g
                    key={il}
                    className="cursor-pointer"
                    onClick={() => onSeciliIlDegisti(il)}
                    role="button"
                    aria-label={`${il.toLocaleLowerCase("tr-TR")}: ${adet} tercih`}
                  >
                    <circle
                      cx={cx}
                      cy={cy}
                      r={11}
                      fill={renk}
                      stroke="white"
                      strokeWidth={2}
                    />
                    <text
                      x={cx}
                      y={cy}
                      textAnchor="middle"
                      dominantBaseline="central"
                      fontSize={11}
                      fontWeight={700}
                      fill="white"
                      className="pointer-events-none select-none"
                    >
                      {adet}
                    </text>
                  </g>
                );
              })
            : null}

          {/* İl seviyesi: üniversite pinleri */}
          {zoomda
            ? acikPinler.map((p) => {
                const r = (p.kilitli ? 7 : 8) * sf;
                const etiket = p.kilitli ? null : kisaUniAdi(p.universite);
                return (
                  <g
                    key={p.id}
                    className={onTercihSec && !p.kilitli ? "cursor-pointer" : undefined}
                    onClick={
                      onTercihSec && !p.kilitli
                        ? () => onTercihSec(p.tercihSiralari[0])
                        : undefined
                    }
                    role={p.kilitli ? undefined : "button"}
                    aria-label={
                      p.kilitli
                        ? "Kilitli tercih"
                        : `${etiket}: ${p.tercihSiralari.length} tercih`
                    }
                  >
                    <circle
                      cx={p.x}
                      cy={p.y}
                      r={r}
                      fill={p.kilitli ? "oklch(0.704 0.04 256.8)" : RISK_RENK[p.risk]}
                      stroke="white"
                      strokeWidth={2 * sf}
                      strokeDasharray={p.kilitli ? `${3 * sf} ${2.5 * sf}` : undefined}
                    />
                    <text
                      x={p.x}
                      y={p.y}
                      textAnchor="middle"
                      dominantBaseline="central"
                      fontSize={9 * sf}
                      fontWeight={700}
                      fill="white"
                      className="pointer-events-none select-none"
                    >
                      {p.kilitli ? "?" : p.tercihSiralari.length}
                    </text>
                    {etiket ? (
                      <text
                        x={p.x}
                        y={p.y - r - 4 * sf}
                        textAnchor="middle"
                        fontSize={10.5 * sf}
                        fontWeight={600}
                        fill="oklch(0.279 0.041 260.0)" // slate-800
                        stroke="white"
                        strokeWidth={3 * sf}
                        paintOrder="stroke"
                        className="pointer-events-none select-none"
                      >
                        {etiket}
                      </text>
                    ) : null}
                  </g>
                );
              })
            : null}
        </svg>

        {zoomda ? (
          <Button
            size="sm"
            variant="outline"
            onClick={() => onSeciliIlDegisti(null)}
            className="absolute left-3 top-3 cursor-pointer rounded-full bg-white/90 backdrop-blur"
          >
            <ArrowLeft className="size-4" aria-hidden />
            Türkiye
          </Button>
        ) : null}
      </div>

      {/* Seçili ilin tercih şeridi (yalnızca zoom'dayken) */}
      {zoomda && seciliPinler.length > 0 ? (
        <div className="mt-2">
          <p className="px-1 pb-1 text-xs font-semibold text-slate-500">
            {seciliIl!.toLocaleLowerCase("tr-TR")} tercihlerin
          </p>
          <ul className="flex gap-2 overflow-x-auto pb-1">
            {seciliPinler
              .flatMap((p) =>
                p.tercihSiralari.map((sira) => ({ pin: p, sira })),
              )
              .sort((a, b) => a.sira - b.sira)
              .map(({ pin, sira }) => (
                <li key={sira} className="shrink-0">
                  <button
                    type="button"
                    onClick={onTercihSec ? () => onTercihSec(sira) : undefined}
                    className="flex cursor-pointer items-center gap-2 rounded-full border border-slate-200 bg-white py-1 pl-1.5 pr-3 text-xs transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50"
                  >
                    <span
                      className="flex size-5 items-center justify-center rounded-full font-heading text-[10px] font-bold text-white"
                      style={{ backgroundColor: RISK_RENK[pin.risk] }}
                    >
                      {sira}
                    </span>
                    {pin.kilitli ? (
                      <span className="inline-flex items-center gap-1 text-slate-400">
                        <Lock className="size-3" aria-hidden />
                        Kilitli tercih
                      </span>
                    ) : (
                      <span className="max-w-40 truncate font-medium text-slate-700">
                        {kisaUniAdi(pin.universite)}
                      </span>
                    )}
                  </button>
                </li>
              ))}
          </ul>
        </div>
      ) : null}
    </div>
  );
}
