/**
 * 泽森排盘 · 全球主要城市库（经纬度 + 冬令UTC时区）
 * 选城即自动填经纬度；水火由纬度算（|纬|/90→水，火=1−水）。
 * © 2026 Jason Li（泽森）
 */
(function (global) {
  "use strict";
  // [键, 中文名, 纬度, 经度, 冬令UTC偏移, 地区码]
  var C = [
    // 东亚
    ["beijing", "北京", 39.9042, 116.4074, 8, "CN", "东亚"],
    ["shanghai", "上海", 31.2304, 121.4737, 8, "CN", "东亚"],
    ["guangzhou", "广州", 23.1291, 113.2644, 8, "CN", "东亚"],
    ["shenzhen", "深圳", 22.5431, 114.0579, 8, "CN", "东亚"],
    ["chengdu", "成都", 30.5728, 104.0668, 8, "CN", "东亚"],
    ["wuhan", "武汉", 30.5928, 114.3055, 8, "CN", "东亚"],
    ["xian", "西安", 34.3416, 108.9398, 8, "CN", "东亚"],
    ["harbin", "哈尔滨", 45.8038, 126.5350, 8, "CN", "东亚"],
    ["hongkong", "香港", 22.3193, 114.1694, 8, "HK", "东亚"],
    ["macau", "澳门", 22.1987, 113.5439, 8, "MO", "东亚"],
    ["taipei", "台北", 25.0330, 121.5654, 8, "TW", "东亚"],
    ["tokyo", "东京", 35.6762, 139.6503, 9, "JP", "东亚"],
    ["osaka", "大阪", 34.6937, 135.5023, 9, "JP", "东亚"],
    ["seoul", "首尔", 37.5665, 126.9780, 9, "KR", "东亚"],
    // 东南亚 / 南亚
    ["singapore", "新加坡", 1.3521, 103.8198, 8, "SG", "东南亚·南亚"],
    ["kualalumpur", "吉隆坡", 3.1390, 101.6869, 8, "MY", "东南亚·南亚"],
    ["bangkok", "曼谷", 13.7563, 100.5018, 7, "TH", "东南亚·南亚"],
    ["jakarta", "雅加达", -6.2088, 106.8456, 7, "ID", "东南亚·南亚"],
    ["manila", "马尼拉", 14.5995, 120.9842, 8, "PH", "东南亚·南亚"],
    ["hanoi", "河内", 21.0278, 105.8342, 7, "VN", "东南亚·南亚"],
    ["newdelhi", "新德里", 28.6139, 77.2090, 5.5, "IN", "东南亚·南亚"],
    ["mumbai", "孟买", 19.0760, 72.8777, 5.5, "IN", "东南亚·南亚"],
    ["dubai", "迪拜", 25.2048, 55.2708, 4, "AE", "东南亚·南亚"],
    // 欧洲
    ["london", "伦敦", 51.5074, -0.1278, 0, "UK", "欧洲"],
    ["paris", "巴黎", 48.8566, 2.3522, 1, "FR", "欧洲"],
    ["berlin", "柏林", 52.5200, 13.4050, 1, "DE", "欧洲"],
    ["madrid", "马德里", 40.4168, -3.7038, 1, "ES", "欧洲"],
    ["rome", "罗马", 41.9028, 12.4964, 1, "IT", "欧洲"],
    ["amsterdam", "阿姆斯特丹", 52.3676, 4.9041, 1, "NL", "欧洲"],
    ["zurich", "苏黎世", 47.3769, 8.5417, 1, "CH", "欧洲"],
    ["moscow", "莫斯科", 55.7558, 37.6173, 3, "RU", "欧洲"],
    ["istanbul", "伊斯坦布尔", 41.0082, 28.9784, 3, "TR", "欧洲"],
    // 北美
    ["newyork", "纽约", 40.7128, -74.0060, -5, "US", "北美"],
    ["losangeles", "洛杉矶", 34.0522, -118.2437, -8, "US", "北美"],
    ["chicago", "芝加哥", 41.8781, -87.6298, -6, "US", "北美"],
    ["houston", "休斯顿", 29.7604, -95.3698, -6, "US", "北美"],
    ["sanfrancisco", "旧金山", 37.7749, -122.4194, -8, "US", "北美"],
    ["seattle", "西雅图", 47.6062, -122.3321, -8, "US", "北美"],
    ["washington", "华盛顿", 38.9072, -77.0369, -5, "US", "北美"],
    ["philadelphia", "费城", 39.9526, -75.1652, -5, "US", "北美"],
    ["boston", "波士顿", 42.3601, -71.0589, -5, "US", "北美"],
    ["lasvegas", "拉斯维加斯", 36.1699, -115.1398, -8, "US", "北美"],
    ["honolulu", "檀香山", 21.3069, -157.8583, -10, "US", "北美"],
    ["toronto", "多伦多", 43.6532, -79.3832, -5, "CA", "北美"],
    ["vancouver", "温哥华", 49.2827, -123.1207, -8, "CA", "北美"],
    ["mexicocity", "墨西哥城", 19.4326, -99.1332, -6, "MX", "北美"],
    // 南美
    ["saopaulo", "圣保罗", -23.5505, -46.6333, -3, "BR", "南美"],
    ["rio", "里约热内卢", -22.9068, -43.1729, -3, "BR", "南美"],
    ["buenosaires", "布宜诺斯艾利斯", -34.6037, -58.3816, -3, "AR", "南美"],
    ["lima", "利马", -12.0464, -77.0428, -5, "PE", "南美"],
    ["santiago", "圣地亚哥", -33.4489, -70.6693, -4, "CL", "南美"],
    ["bogota", "波哥大", 4.7110, -74.0721, -5, "CO", "南美"],
    // 大洋洲
    ["sydney", "悉尼", -33.8688, 151.2093, 10, "AU", "大洋洲"],
    ["melbourne", "墨尔本", -37.8136, 144.9631, 10, "AU", "大洋洲"],
    ["perth", "珀斯", -31.9505, 115.8605, 8, "AU", "大洋洲"],
    ["auckland", "奥克兰", -36.8485, 174.7633, 12, "NZ", "大洋洲"],
    // 非洲 / 中东
    ["cairo", "开罗", 30.0444, 31.2357, 2, "EG", "非洲·中东"],
    ["johannesburg", "约翰内斯堡", -26.2041, 28.0473, 2, "ZA", "非洲·中东"],
    ["lagos", "拉各斯", 6.5244, 3.3792, 1, "NG", "非洲·中东"],
    ["nairobi", "内罗毕", -1.2921, 36.8219, 3, "KE", "非洲·中东"],
    ["riyadh", "利雅得", 24.7136, 46.6753, 3, "SA", "非洲·中东"],
    ["telaviv", "特拉维夫", 32.0853, 34.7818, 2, "IL", "非洲·中东"],
  ];
  var TZ = {
    beijing: "Asia/Shanghai", shanghai: "Asia/Shanghai", guangzhou: "Asia/Shanghai", shenzhen: "Asia/Shanghai",
    chengdu: "Asia/Shanghai", wuhan: "Asia/Shanghai", xian: "Asia/Shanghai", harbin: "Asia/Shanghai",
    hongkong: "Asia/Hong_Kong", macau: "Asia/Macau", taipei: "Asia/Taipei",
    tokyo: "Asia/Tokyo", osaka: "Asia/Tokyo", seoul: "Asia/Seoul",
    singapore: "Asia/Singapore", kualalumpur: "Asia/Kuala_Lumpur", bangkok: "Asia/Bangkok",
    jakarta: "Asia/Jakarta", manila: "Asia/Manila", hanoi: "Asia/Bangkok",
    newdelhi: "Asia/Kolkata", mumbai: "Asia/Kolkata", dubai: "Asia/Dubai",
    london: "Europe/London", paris: "Europe/Paris", berlin: "Europe/Berlin",
    madrid: "Europe/Madrid", rome: "Europe/Rome", amsterdam: "Europe/Amsterdam",
    zurich: "Europe/Zurich", moscow: "Europe/Moscow", istanbul: "Europe/Istanbul",
    newyork: "America/New_York", losangeles: "America/Los_Angeles", chicago: "America/Chicago",
    houston: "America/Chicago", sanfrancisco: "America/Los_Angeles", seattle: "America/Los_Angeles",
    washington: "America/New_York", philadelphia: "America/New_York", boston: "America/New_York", lasvegas: "America/Los_Angeles",
    honolulu: "Pacific/Honolulu", toronto: "America/Toronto", vancouver: "America/Vancouver",
    mexicocity: "America/Mexico_City",
    saopaulo: "America/Sao_Paulo", rio: "America/Sao_Paulo", buenosaires: "America/Argentina/Buenos_Aires",
    lima: "America/Lima", santiago: "America/Santiago", bogota: "America/Bogota",
    sydney: "Australia/Sydney", melbourne: "Australia/Melbourne", perth: "Australia/Perth",
    auckland: "Pacific/Auckland",
    cairo: "Africa/Cairo", johannesburg: "Africa/Johannesburg", lagos: "Africa/Lagos",
    nairobi: "Africa/Nairobi", riyadh: "Asia/Riyadh", telaviv: "Asia/Jerusalem",
  };
  var byId = {}, groups = {};
  C.forEach(function (r) {
    var o = { id: r[0], name: r[1], lat: r[2], lng: r[3], zone: r[4], region2: r[5], group: r[6], tz: TZ[r[0]] || null };
    byId[r[0]] = o;
    (groups[o.group] = groups[o.group] || []).push(o);
  });
  function distKm(aLat, aLon, bLat, bLon) {
    var R = 6371, toR = Math.PI / 180;
    var dLat = (bLat - aLat) * toR, dLon = (bLon - aLon) * toR;
    var s = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
      Math.cos(aLat * toR) * Math.cos(bLat * toR) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
    return 2 * R * Math.asin(Math.min(1, Math.sqrt(s)));
  }
  function nearest(lat, lon, maxKm) {
    maxKm = maxKm == null ? 180 : maxKm;
    var best = null, bestD = Infinity;
    C.forEach(function (r) {
      var d = distKm(lat, lon, r[2], r[3]);
      if (d < bestD) { bestD = d; best = byId[r[0]]; }
    });
    if (!best || bestD > maxKm) return { city: null, km: bestD };
    return { city: best, km: bestD };
  }
  function byDeviceTz() {
    var tz = "";
    try { tz = Intl.DateTimeFormat().resolvedOptions().timeZone || ""; } catch (e) { tz = ""; }
    if (tz) {
      var ids = Object.keys(TZ);
      for (var i = 0; i < ids.length; i++) {
        if (TZ[ids[i]] === tz) return byId[ids[i]];
      }
    }
    var offH = -new Date().getTimezoneOffset() / 60;
    var hit = null, hitD = 99;
    C.forEach(function (r) {
      var d = Math.abs((r[4] || 0) - offH);
      if (d < hitD) { hitD = d; hit = byId[r[0]]; }
    });
    return hitD <= 0.51 ? hit : null;
  }
  function nowAtCity(cityId, zoneFallback) {
    var o = cityId && byId[cityId], tz = o && o.tz;
    if (tz) {
      try {
        var parts = new Intl.DateTimeFormat("en-CA", {
          timeZone: tz, year: "numeric", month: "2-digit", day: "2-digit",
          hour: "2-digit", minute: "2-digit", hourCycle: "h23",
        }).formatToParts(new Date());
        var g = {};
        parts.forEach(function (p) { if (p.type !== "literal") g[p.type] = p.value; });
        return { y: +g.year, mo: +g.month, d: +g.day, h: +g.hour, mi: +g.minute, tz: tz };
      } catch (e) { /* fall through */ }
    }
    var z = (o && o.zone != null) ? o.zone : (zoneFallback != null ? zoneFallback : 0);
    var x = new Date(Date.now() + z * 3600000);
    return { y: x.getUTCFullYear(), mo: x.getUTCMonth() + 1, d: x.getUTCDate(), h: x.getUTCHours(), mi: x.getUTCMinutes(), tz: "UTC" + (z >= 0 ? "+" : "") + z };
  }
  function nowAtLonLat(lat, lon, zoneFallback) {
    var n = nearest(lat, lon, 180);
    if (n.city) return nowAtCity(n.city.id, n.city.zone);
    var z = zoneFallback != null ? zoneFallback : Math.round((Number(lon) || 0) / 15);
    if (z > 14) z = 14;
    if (z < -12) z = -12;
    return nowAtCity(null, z);
  }
  global.KRCities = { list: C, byId: byId, groups: groups, tz: TZ, nowAtCity: nowAtCity, nowAtLonLat: nowAtLonLat, nearest: nearest, byDeviceTz: byDeviceTz, distKm: distKm };
})(typeof window !== "undefined" ? window : globalThis);
