const KZ_MAP_VIEW = { x: 110, y: 70, width: 1710, height: 940 };
const KZ_MAP_ASPECT = KZ_MAP_VIEW.width / KZ_MAP_VIEW.height;
const KZ_COUNTRY_PATH =
  "M1749.27,501.31 L1719.88,540.39 L1687.83,545.83 L1685.98,603.63 L1664.51,629.33 L1587.94,610.64 L1560.08,710.93 L1540.32,723.18 L1463.86,745.03 L1498.60,838.34 L1472.12,852.09 L1475.20,882.00 L1451.41,874.33 L1432.05,855.46 L1374.78,849.95 L1310.77,848.51 L1296.75,854.31 L1241.77,832.09 L1219.87,843.05 L1213.86,874.11 L1150.36,856.02 L1124.95,863.44 L1116.30,886.38 L1094.17,896.01 L1043.26,932.06 L1026.37,968.68 L1011.98,969.00 L1001.41,944.81 L952.31,943.15 L944.46,900.87 L925.65,900.51 L928.53,848.00 L882.32,809.21 L816.12,813.38 L770.86,821.14 L733.99,772.80 L702.41,752.30 L642.57,713.12 L635.36,708.33 L535.99,740.76 L537.51,935.95 L517.71,938.46 L490.69,897.95 L464.60,883.35 L420.78,894.20 L403.73,911.47 L401.56,898.82 L411.05,877.09 L403.69,858.82 L358.95,840.85 L341.54,792.99 L320.22,779.38 L318.93,761.76 L356.48,766.91 L357.97,727.08 L390.79,718.16 L424.51,726.36 L431.46,672.39 L424.58,637.69 L385.96,640.42 L353.14,626.62 L308.45,651.43 L272.44,663.19 L252.83,654.12 L256.75,625.10 L232.14,586.98 L203.50,588.59 L170.73,549.41 L193.01,505.02 L181.74,492.96 L212.54,427.11 L252.23,462.05 L257.04,417.97 L336.72,351.04 L397.02,349.43 L482.11,392.24 L527.81,416.96 L568.77,391.18 L629.96,389.95 L679.33,421.60 L690.55,403.52 L744.77,406.15 L754.44,377.08 L691.89,334.32 L728.94,303.64 L721.71,286.33 L758.76,269.71 L730.90,225.44 L748.60,203.12 L893.04,180.17 L911.89,163.76 L1008.48,139.04 L1043.18,111.00 L1112.55,125.61 L1124.71,194.76 L1165.01,178.68 L1214.59,201.19 L1211.39,236.83 L1248.41,233.13 L1345.16,171.12 L1331.03,191.88 L1380.28,242.37 L1466.54,402.14 L1487.11,369.93 L1540.28,405.35 L1595.75,389.61 L1617.06,400.64 L1635.64,435.78 L1662.63,447.49 L1679.06,472.93 L1728.79,464.93 L1749.27,501.31 Z";

const KZ_CITIES = [
  { id: "almaty", name: "Алматы", sourceName: "Almaty", x: 1346.08, y: 835.18, labelDx: 132, labelDy: 108, hub: true, days: "0–1", free: true, note: "Бесплатная доставка в торговые точки: Car City, Жибек Жолы, Кенжехан, Бақорда" },
  { id: "astana", name: "Астана", sourceName: "Astana", x: 1134.05, y: 384.81, labelDx: 38, labelDy: -50, days: "1–3", free: true },
  { id: "shymkent", name: "Шымкент", sourceName: "Shymkent", x: 1063.55, y: 883.74, labelDx: -112, labelDy: 64, days: "1–3", free: true },
  { id: "aktobe", name: "Ақтөбе", sourceName: "Aktobe", x: 586.21, y: 437.46, labelDx: -132, labelDy: -22, days: "4–6", free: true },
  { id: "karaganda", name: "Қарағанды", sourceName: "Karaganda", x: 1199.03, y: 466.36, labelDx: 46, labelDy: 52, days: "1–3", free: true },
  { id: "taraz", name: "Тараз", sourceName: "Taraz", x: 1131.91, y: 853.15, labelDx: 76, labelDy: 88, days: "1–3", free: true },
  { id: "ust", name: "Өскемен", sourceName: "Oskemen", x: 1566.17, y: 455.54, labelDx: -154, labelDy: -16, days: "1–3", free: true },
  { id: "pavlodar", name: "Павлодар", sourceName: "Pavlodar", x: 1347.43, y: 312.97, labelDx: 44, labelDy: -34, days: "1–3", free: true },
  { id: "atyrau", name: "Атырау", sourceName: "Atyrau", x: 379.83, y: 622.77, labelDx: -118, labelDy: -42, days: "4–6", free: true },
  { id: "semey", name: "Семей", sourceName: "Semey", x: 1475.46, y: 428.4, labelDx: 48, labelDy: 28, days: "1–3", free: true },
  { id: "aktau", name: "Ақтау", sourceName: "Aktau", x: 351.81, y: 813.25, labelDx: -118, labelDy: 36, days: "4–6", free: true },
  { id: "kyzylorda", name: "Қызылорда", sourceName: "Kyzylorda", x: 906.09, y: 748.71, labelDx: -138, labelDy: 58, days: "1–3", free: true },
  { id: "kostanay", name: "Қостанай", sourceName: "Kostanay", x: 832.88, y: 255.57, labelDx: -126, labelDy: -24, days: "1–3", free: true },
  { id: "uralsk", name: "Орал", sourceName: "Oral", x: 360.11, y: 380.17, labelDx: -118, labelDy: 24, days: "4–6", free: true },
  { id: "turkistan", name: "Түркістан", sourceName: "Turkistan", x: 1012.34, y: 831.9, labelDx: -126, labelDy: -58, days: "1–3", free: true },
  { id: "petropavl", name: "Петропавл", sourceName: "Petropavl", x: 1046.99, y: 144.89, labelDx: -108, labelDy: -12, days: "1–3", free: true },
  { id: "kokshetau", name: "Көкшетау", sourceName: "Kokshetau", x: 1055.35, y: 250.2, labelDx: 48, labelDy: -46, days: "1–3", free: true },
  { id: "taldykorgan", name: "Талдықорған", sourceName: "Taldykorgan", x: 1402.12, y: 739.62, labelDx: 58, labelDy: -42, days: "1–3", free: true },
  { id: "temirtau", name: "Темиртау", sourceName: "Temirtau", x: 1193.03, y: 451.54, labelDx: 48, labelDy: -42 },
  { id: "ekibastuz", name: "Экибастуз", sourceName: "Ekibastuz", x: 1286.31, y: 352.66, labelDx: 50, labelDy: -10 },
  { id: "rudny", name: "Рудный", sourceName: "Rudny", x: 814.09, y: 270.56, labelDx: 44, labelDy: 36 },
  { id: "zhezkazgan", name: "Жезқазған", sourceName: "Zhezkazgan", x: 990.37, y: 584.71, labelDx: -142, labelDy: 12, days: "1–3", free: true },
  { id: "kaskelen", name: "Каскелен", sourceName: "Kaskelen", x: 1334.69, y: 837.3, labelDx: -176, labelDy: 44 },
  { id: "zhanaozen", name: "Жанаозен", sourceName: "Zhanaozen", x: 417.35, y: 829.99, labelDx: -132, labelDy: -28 },
  { id: "kentau", name: "Кентау", sourceName: "Kentau", x: 1021.9, y: 820.49, labelDx: 62, labelDy: -8 },
  { id: "balkhash", name: "Балхаш", sourceName: "Balkhash", x: 1271.97, y: 637.96, labelDx: 54, labelDy: 30 },
  { id: "satbayev", name: "Сатпаев", sourceName: "Satbayev", x: 983.94, y: 578, labelDx: 48, labelDy: 50 },
  { id: "talgar", name: "Талгар", sourceName: "Talgar", x: 1358.37, y: 832, labelDx: 156, labelDy: 36 },
  { id: "kosshy", name: "Косшы", sourceName: "Kosshy", x: 1131.36, y: 395.46, labelDx: 48, labelDy: 42 },
  { id: "kulsary", name: "Кульсары", sourceName: "Kulsary", x: 462.18, y: 630.32, labelDx: -116, labelDy: 18 },
  { id: "saryagash", name: "Сарыағаш", sourceName: "Saryagash", x: 1046.99, y: 927.82, labelDx: 72, labelDy: 96, days: "1–3", free: true },
  { id: "qonaev", name: "Қонаев", sourceName: "Qonaev", x: 1352.01, y: 800.85, labelDx: 70, labelDy: -86 },
  { id: "arys", name: "Арысь", sourceName: "Arys", x: 1032.83, y: 877.65, labelDx: -112, labelDy: 74 },
  { id: "alatau", name: "Алатау", sourceName: "Alatau", x: 1353.59, y: 812.17, labelDx: 170, labelDy: 2 },
  { id: "zharkent", name: "Жаркент", sourceName: "Zharkent", x: 1465.16, y: 785.7, labelDx: 46, labelDy: 48 },
  { id: "aksu", name: "Аксу", sourceName: "Aksu", x: 1346.15, y: 329.75, labelDx: 54, labelDy: 52 },
  { id: "aksay", name: "Ақсай", sourceName: "Aksay", x: 423, y: 383, labelDx: 48, labelDy: 42, days: "4–6", free: true },
  { id: "beyneu", name: "Бейнеу", sourceName: "Beyneu", x: 503, y: 721, labelDx: 54, labelDy: -32, days: "4–6", free: true },
  { id: "shetpe", name: "Шетпе", sourceName: "Shetpe", x: 388, y: 800, labelDx: -118, labelDy: 40, days: "4–6", free: true },
];

function getKZMapViewBox(city) {
  if (!city) {
    return `${KZ_MAP_VIEW.x} ${KZ_MAP_VIEW.y} ${KZ_MAP_VIEW.width} ${KZ_MAP_VIEW.height}`;
  }

  const width = 820;
  const height = width / KZ_MAP_ASPECT;
  const maxX = KZ_MAP_VIEW.x + KZ_MAP_VIEW.width - width;
  const maxY = KZ_MAP_VIEW.y + KZ_MAP_VIEW.height - height;
  const x = Math.max(KZ_MAP_VIEW.x, Math.min(maxX, city.x - width / 2));
  const y = Math.max(KZ_MAP_VIEW.y, Math.min(maxY, city.y - height / 2));
  return `${x} ${y} ${width} ${height}`;
}

function parseViewBox(viewBox) {
  return viewBox.split(" ").map(Number);
}

function formatViewBox(values) {
  return values.map((value) => value.toFixed(2)).join(" ");
}

function viewBoxToZoomView(viewBox) {
  const [x, y, width, height] = parseViewBox(viewBox);
  return [x + width / 2, y + height / 2, width];
}

function zoomViewToViewBox(view) {
  const [centerX, centerY, width] = view;
  const height = width / KZ_MAP_ASPECT;
  return [
    centerX - width / 2,
    centerY - height / 2,
    width,
    height,
  ];
}

function easeInOutCubic(t) {
  return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
}

function getCityLabelPoint(city) {
  const maxDistance = city.hub ? 44 : 34;
  const length = Math.hypot(city.labelDx, city.labelDy) || 1;
  const scale = Math.min(1, maxDistance / length);
  return {
    x: city.x + city.labelDx * scale,
    y: city.y + city.labelDy * scale,
    anchor: city.labelDx < 0 ? "end" : "start",
  };
}

function getDeliveryDays(city) {
  if (city.days) return city.days;
  return "2–4";
}

function getDeliveryCost(city) {
  if (city.free) return "Бесплатно";
  return "Бесплатная доставка при заказе до 30 кг";
}

function KZMap({ t, accent, selectedCity, onSelectCity }) {
  const [hovered, setHovered] = React.useState(null);
  const [animatedViewBox, setAnimatedViewBox] = React.useState(getKZMapViewBox(null));
  const animationRef = React.useRef(null);
  const animatedViewBoxRef = React.useRef(getKZMapViewBox(null));
  const cities = KZ_CITIES;
  const activeCityId = hovered || selectedCity;
  const activeCity = cities.find((city) => city.id === activeCityId);
  const selectedCityData = cities.find((city) => city.id === selectedCity);
  const hubCity = cities.find((city) => city.hub);
  const targetViewBox = getKZMapViewBox(selectedCityData);
  const deliveryCities = cities.filter((city) => city.days && !city.hub);

  React.useEffect(() => {
    const startBox = parseViewBox(animatedViewBoxRef.current);
    const endBox = parseViewBox(targetViewBox);
    const startView = viewBoxToZoomView(animatedViewBoxRef.current);
    const endView = viewBoxToZoomView(targetViewBox);
    const interpolateZoom = window.d3?.interpolateZoom?.(startView, endView);
    const duration = interpolateZoom
      ? Math.max(520, Math.min(980, interpolateZoom.duration * 0.72))
      : 680;
    let startedAt = null;

    if (animationRef.current) {
      cancelAnimationFrame(animationRef.current);
    }

    const tick = (now) => {
      if (startedAt === null) startedAt = now;
      const progress = Math.min(1, (now - startedAt) / duration);
      const next = interpolateZoom
        ? zoomViewToViewBox(interpolateZoom(progress))
        : startBox.map((value, index) => {
            const eased = easeInOutCubic(progress);
            return value + (endBox[index] - value) * eased;
          });
      const formatted = formatViewBox(next);

      animatedViewBoxRef.current = formatted;
      setAnimatedViewBox(formatted);

      if (progress < 1) {
        animationRef.current = requestAnimationFrame(tick);
      } else {
        animatedViewBoxRef.current = targetViewBox;
        setAnimatedViewBox(targetViewBox);
        animationRef.current = null;
      }
    };

    animationRef.current = requestAnimationFrame(tick);

    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [targetViewBox]);

  return (
    <div className="kz-map-wrap">
      <svg
        viewBox={animatedViewBox}
        className="kz-map-svg"
        xmlns="http://www.w3.org/2000/svg"
        aria-label="Карта доставки по Казахстану"
      >
        <defs>
          <pattern id="dots" x="0" y="0" width="18" height="18" patternUnits="userSpaceOnUse">
            <circle cx="2" cy="2" r="1.2" fill="rgba(255,255,255,0.06)" />
          </pattern>
          <filter id="kzShapeEdge" x="-5%" y="-5%" width="110%" height="110%">
            <feDropShadow dx="0" dy="0" stdDeviation="2.4" floodColor="#2a6fa7" floodOpacity="0.55" />
          </filter>
        </defs>

        <path d={KZ_COUNTRY_PATH} fill="#082a47" stroke="rgba(90,166,225,0.45)" strokeWidth="2.6" filter="url(#kzShapeEdge)" />
        <path d={KZ_COUNTRY_PATH} fill="url(#dots)" opacity="0.9" />

        {[320, 240, 160].map((r, i) => (
          <circle
            key={i}
            cx={hubCity.x}
            cy={hubCity.y}
            r={r}
            fill="none"
            stroke={accent}
            strokeOpacity={0.08 + i * 0.04}
            strokeWidth="1.4"
            strokeDasharray="8 10"
          />
        ))}

        {deliveryCities.map((city) => (
          <line
            key={"line-" + city.id}
            x1={hubCity.x}
            y1={hubCity.y}
            x2={city.x}
            y2={city.y}
            stroke={city.free ? accent : "rgba(255,255,255,0.16)"}
            strokeWidth={activeCityId === city.id ? 2.2 : 1}
            strokeOpacity={activeCityId === city.id ? 0.9 : (city.free ? 0.25 : 0.16)}
            strokeDasharray={city.free ? "none" : "4 7"}
          />
        ))}

        {cities.map((city) => {
          const isActive = activeCityId === city.id;
          const showLabel = hovered === city.id;
          const isDeliveryCity = Boolean(city.days);
          const label = getCityLabelPoint(city);
          return (
            <g
              key={city.id}
              onMouseEnter={() => setHovered(city.id)}
              onMouseLeave={() => setHovered(null)}
            >
              {city.hub && (
                <>
                  <circle cx={city.x} cy={city.y} r="42" fill={accent} opacity="0.14" />
                  <circle cx={city.x} cy={city.y} r="26" fill={accent} opacity="0.28">
                    <animate attributeName="r" values="26;42;26" dur="2.4s" repeatCount="indefinite" />
                    <animate attributeName="opacity" values="0.28;0;0.28" dur="2.4s" repeatCount="indefinite" />
                  </circle>
                </>
              )}
              <circle
                cx={city.x}
                cy={city.y}
                r={city.hub ? 12 : (isActive ? 10 : 7)}
                fill={city.hub ? "#666" : accent}
                stroke="#001427"
                strokeWidth="4"
              />
              <line
                x1={city.x}
                y1={city.y}
                x2={label.x}
                y2={label.y - 6}
                stroke="rgba(255,255,255,0.2)"
                strokeWidth={showLabel ? 1.4 : 0.8}
                opacity={showLabel ? 1 : 0}
                pointerEvents="none"
              />
              <text
                x={label.x}
                y={label.y}
                textAnchor={label.anchor}
                fill="#fff"
                fontSize={showLabel ? "24" : "18"}
                fontWeight={showLabel ? "800" : "650"}
                fontFamily="Manrope, sans-serif"
                opacity={showLabel ? 1 : 0}
                paintOrder="stroke"
                stroke="#001427"
                strokeWidth="6"
                strokeLinejoin="round"
                pointerEvents="none"
              >
                {city.name}
              </text>
              <circle cx={city.x} cy={city.y} r="24" fill="transparent" />
            </g>
          );
        })}
      </svg>

      <div className="kz-map-info">
        {activeCity ? (() => {
          const c = activeCity;
          return (
            <div className="kz-info-card">
              <div className="kz-info-name">{c.name}</div>
              {c.days && (
                <div className="kz-info-row">
                  <span className="kz-info-label">Срок доставки</span>
                  <span className="kz-info-value">{c.days} дн.</span>
                </div>
              )}
              {c.free ? (
                <div className="kz-info-row">
                  <span className="kz-info-label">Стоимость</span>
                  <span className="kz-info-value free">Бесплатно</span>
                </div>
              ) : (
                <div className="kz-info-cond">
                  <svg className="kz-info-cond-icon" width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <circle cx="8" cy="8" r="7" stroke="currentColor" strokeWidth="1.5"/>
                    <path d="M5 8.5L7 10.5L11 6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
                  </svg>
                  Бесплатная доставка при заказе до 30 кг
                </div>
              )}
              {c.note && (
                <div className="kz-info-note">{c.note}</div>
              )}
            </div>
          );
        })() : (
          <div className="kz-info-card kz-info-empty">
            <div className="kz-info-empty-title">{t.coverage.hover}</div>
            <div className="kz-info-legend">
              <div className="kz-leg-row">
                <span className="kz-leg-dot hub" /> {t.coverage.hub} — Алматы
              </div>
              <div className="kz-leg-row">
                <span className="kz-leg-dot free" /> {t.coverage.cities}
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

window.KZMap = KZMap;
window.KZ_CITIES = KZ_CITIES;
