import { ipInCidrV4, parseCidrV4 } from "./traffic-flow-ip.js"

export const OTHER_SERVICE = "Прочее"

export interface BrandHit {
  service: string
  category: string
}

const ASN_BRANDS = new Map<number, BrandHit>([
  [13335, { service: "Cloudflare", category: "CDN" }],
  [209242, { service: "Cloudflare", category: "CDN" }],
  [54113, { service: "Fastly", category: "CDN" }],
  [20940, { service: "Akamai", category: "CDN" }],
  [16509, { service: "AWS", category: "CDN" }],
  [14618, { service: "AWS", category: "CDN" }],
  [8075, { service: "Microsoft", category: "CDN" }],
  [13238, { service: "Yandex", category: "CDN" }],
  [32590, { service: "Steam", category: "Игры" }],
  [57976, { service: "Blizzard", category: "Игры" }],
  [2906, { service: "Netflix", category: "Видео / стриминг" }],
  [40027, { service: "Netflix", category: "Видео / стриминг" }],
  [15169, { service: "Google", category: "Веб" }],
  [36040, { service: "YouTube", category: "Видео / стриминг" }],
  [46489, { service: "Twitch", category: "Видео / стриминг" }],
  [401115, { service: "ChatGPT", category: "ИИ" }],
  [49544, { service: "Discord", category: "Голос" }],
  [62041, { service: "Telegram", category: "Голос" }],
  [59930, { service: "Telegram", category: "Голос" }],
  [211157, { service: "Telegram", category: "Голос" }],
  [32934, { service: "Meta", category: "CDN" }],
  [396986, { service: "TikTok", category: "Видео / стриминг" }],
])

const ASN_HQ_COUNTRY = new Map<number, string>([
  [13335, "US"],
  [209242, "US"],
  [54113, "US"],
  [20940, "US"],
  [16509, "US"],
  [14618, "US"],
  [8075, "US"],
  [15169, "US"],
  [32590, "US"],
  [57976, "US"],
  [2906, "US"],
  [40027, "US"],
  [36040, "US"],
  [46489, "US"],
  [401115, "US"],
  [49544, "US"],
  [32934, "US"],
  [13238, "RU"],
  [62041, "NL"],
  [59930, "NL"],
  [211157, "NL"],
])

const GOOGLE: BrandHit = { service: "Google", category: "Веб" }
const CLOUDFLARE: BrandHit = { service: "Cloudflare", category: "CDN" }
const YOUTUBE: BrandHit = { service: "YouTube", category: "Видео / стриминг" }

const CIDR_BRANDS: Array<{ cidr: string; prefixLen: number; hit: BrandHit }> = [
  { cidr: "104.16.0.0/13", prefixLen: 13, hit: CLOUDFLARE },
  { cidr: "104.24.0.0/14", prefixLen: 14, hit: CLOUDFLARE },
  { cidr: "172.64.0.0/13", prefixLen: 13, hit: CLOUDFLARE },
  { cidr: "162.158.0.0/15", prefixLen: 15, hit: CLOUDFLARE },
  { cidr: "8.8.8.0/24", prefixLen: 24, hit: GOOGLE },
  { cidr: "8.8.4.0/24", prefixLen: 24, hit: GOOGLE },
  { cidr: "173.194.0.0/16", prefixLen: 16, hit: GOOGLE },
  { cidr: "172.217.0.0/16", prefixLen: 16, hit: GOOGLE },
  { cidr: "74.125.0.0/16", prefixLen: 16, hit: GOOGLE },
  { cidr: "142.250.0.0/15", prefixLen: 15, hit: GOOGLE },
  { cidr: "208.65.152.0/22", prefixLen: 22, hit: YOUTUBE },
  { cidr: "208.117.224.0/19", prefixLen: 19, hit: YOUTUBE },
].sort((a, b) => b.prefixLen - a.prefixLen)

const NON_ISO = new Set(["EU", "AP", "ZZ", "XX", "A1", "A2", "O1"])

export function isIsoCountry(code: string): boolean {
  const c = String(code ?? "").trim().toUpperCase()
  return /^[A-Z]{2}$/.test(c) && !NON_ISO.has(c)
}

export function normalizeIsoCountry(code: string): string {
  const c = String(code ?? "").trim().toUpperCase()
  return isIsoCountry(c) ? c : ""
}

/** `CLOUDFLARENET, US` → `US`. */
export function countryFromHolder(holder: string): string {
  const m = String(holder ?? "").trim().match(/,\s*([A-Za-z]{2})\s*$/)
  return m?.[1] ? normalizeIsoCountry(m[1]) : ""
}

export function countryForAsn(asn: number): string {
  if (!asn) return ""
  return ASN_HQ_COUNTRY.get(asn) ?? ""
}

export function resolveRipeCountry(country: string, asn: number, holder: string): string {
  return normalizeIsoCountry(country) || countryFromHolder(holder) || countryForAsn(asn)
}

export function brandByAsn(asn: number): BrandHit | null {
  if (!asn) return null
  return ASN_BRANDS.get(asn) ?? null
}

export function brandByCidr(ip: string): BrandHit | null {
  for (const row of CIDR_BRANDS) {
    if (parseCidrV4(row.cidr) && ipInCidrV4(ip, row.cidr)) return row.hit
  }
  return null
}

export function lookupBrand(ip: string, asn: number): BrandHit | null {
  return brandByCidr(ip) || brandByAsn(asn)
}

const SKIP_MAP_SERVICES = new Set([
  OTHER_SERVICE,
  "GRE",
  "ESP",
  "WireGuard",
  "DNS",
  "SSH",
  "BGP",
])

const SKIP_MAP_CATEGORIES = new Set(["Туннель", "DNS", "SSH", "BGP"])

/** Именованный интернет-сервис для карты (не туннель и не «Прочее»). */
export function isNamedInternetService(service: string, category: string): boolean {
  const s = service.trim()
  const c = category.trim()
  if (!s || SKIP_MAP_SERVICES.has(s) || SKIP_MAP_CATEGORIES.has(c)) return false
  return true
}

export function mapServiceNodeId(label: string): string {
  const slug = label
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
  return `svc:${slug || "unknown"}`
}
