import { z } from 'zod'

export const CENSORCHECK_STATUSES = [
  'available',
  'redirected',
  'denied',
  'blocked',
  'timeout',
  'error',
] as const

export type CensorcheckStatus = (typeof CENSORCHECK_STATUSES)[number]

export const CENSORCHECK_CATEGORIES = ['dpi', 'geoblock', 'custom'] as const

export type CensorcheckCategory = (typeof CENSORCHECK_CATEGORIES)[number]

export const CENSORCHECK_RUN_STATUSES = ['complete', 'partial'] as const

export type CensorcheckRunStatus = (typeof CENSORCHECK_RUN_STATUSES)[number]

/** DPI-сервисы из vernette/censorcheck (pin 12c5839). */
export const CENSORCHECK_DPI_HOSTS = [
  'youtube.com',
  'redirector.googlevideo.com',
  'discord.com',
  'instagram.com',
  'facebook.com',
  'x.com',
  'linkedin.com',
  'rutracker.org',
  'digitalocean.com',
  'amnezia.org',
  'getoutline.org',
  'mailfence.com',
  'flibusta.is',
  'rezka.ag',
  'api.telegram.org',
  'play.google.com',
] as const

/** Геоблок-сервисы из vernette/censorcheck (pin 12c5839). */
export const CENSORCHECK_GEOBLOCK_HOSTS = [
  'spotify.com',
  'netflix.com',
  'patreon.com',
  'swagger.io',
  'snyk.io',
  'mongodb.com',
  'autodesk.com',
  'graylog.org',
  'redis.io',
  'copilot.microsoft.com',
] as const

const DPI_SET = new Set<string>(CENSORCHECK_DPI_HOSTS)
const GEO_SET = new Set<string>(CENSORCHECK_GEOBLOCK_HOSTS)

export function inferCensorcheckCategory(serviceKey: string): CensorcheckCategory {
  const key = serviceKey.trim().toLowerCase()
  if (DPI_SET.has(key)) return 'dpi'
  if (GEO_SET.has(key)) return 'geoblock'
  return 'custom'
}

export const censorcheckStatusSchema = z.enum(CENSORCHECK_STATUSES)
export const censorcheckCategorySchema = z.enum(CENSORCHECK_CATEGORIES)

export const censorcheckIngestResultSchema = z.object({
  service: z.string().trim().min(1).max(253),
  category: censorcheckCategorySchema.optional(),
  raw: z.record(z.unknown()).default({}),
})

export const censorcheckIngestBodySchema = z.object({
  schemaVersion: z.literal(1),
  runId: z.string().trim().min(8).max(80),
  probe: z.object({
    publicIp: z.string().trim().min(1).max(64),
    hoster: z.string().trim().max(160).optional(),
  }),
  censorcheck: z
    .object({
      version: z.string().trim().max(32).optional(),
      mode: z.string().trim().max(32).optional(),
    })
    .optional(),
  launcherVersion: z.string().trim().max(32).optional(),
  results: z.array(censorcheckIngestResultSchema).min(1).max(200),
})

export type CensorcheckIngestBody = z.infer<typeof censorcheckIngestBodySchema>
export type CensorcheckIngestResult = z.infer<typeof censorcheckIngestResultSchema>

export type CensorcheckSummary = {
  total: number
  available: number
  redirected: number
  denied: number
  blocked: number
  timeout: number
  error: number
}

export function emptyCensorcheckSummary(): CensorcheckSummary {
  return {
    total: 0,
    available: 0,
    redirected: 0,
    denied: 0,
    blocked: 0,
    timeout: 0,
    error: 0,
  }
}

const HOSTER_ALIASES: ReadonlyArray<{ test: RegExp; name: string }> = [
  { test: /digitalocean|digital ocean|\bas14061\b/i, name: 'DigitalOcean' },
  { test: /hetzner|\bas24940\b/i, name: 'Hetzner' },
  { test: /\bovh|\bas16276\b/i, name: 'OVH' },
  { test: /linode|akamai|\bas63949\b/i, name: 'Linode' },
  { test: /\bvultr|\bas20473\b/i, name: 'Vultr' },
  { test: /amazon|aws|\bec2\b|\bas16509\b|\bas14618\b/i, name: 'AWS' },
  { test: /google cloud|\bgcp\b|\bas15169\b/i, name: 'Google Cloud' },
  { test: /microsoft|azure|\bas8075\b/i, name: 'Azure' },
  { test: /oracle cloud|\bas31898\b/i, name: 'Oracle Cloud' },
  { test: /selectel|\bas49505\b/i, name: 'Selectel' },
  { test: /timeweb|\bas197695\b/i, name: 'Timeweb' },
  { test: /vdsina/i, name: 'VDSina' },
  { test: /4vps/i, name: '4VPS' },
  { test: /macloud/i, name: 'Macloud' },
  { test: /veesp/i, name: 'Veesp' },
  { test: /ruvds|ru-vds|ru vds/i, name: 'RUVDS' },
  { test: /\baeza\b/i, name: 'Aeza' },
  { test: /firstvds|firstdedic/i, name: 'FirstVDS' },
  { test: /yandex cloud|\bas200350\b/i, name: 'Yandex Cloud' },
  { test: /cloud\.ru|sbercloud|\bas208677\b/i, name: 'Cloud.ru' },
  { test: /\bbeget\b/i, name: 'Beget' },
  { test: /fornex/i, name: 'Fornex' },
  { test: /adminvps/i, name: 'AdminVPS' },
  { test: /\bihor\b/i, name: 'Ihor' },
  { test: /netcup/i, name: 'Netcup' },
  { test: /contabo/i, name: 'Contabo' },
  { test: /leaseweb/i, name: 'Leaseweb' },
]

function tidyOrgName(value: string): string {
  const stripped = value
    .replace(/^as\d+\s+/i, '')
    .replace(/\s*[,;]?\s*\b(llc|ltd|inc|gmbh|corp|limited|jsc|ooo|ооо|ао)\b\.?$/i, '')
    .replace(/\s+/g, ' ')
    .trim()
  if (!stripped) return value.slice(0, 80)
  const words = stripped.split(' ')
  if (stripped.length > 42 && words.length > 3) return words.slice(0, 3).join(' ')
  return stripped.slice(0, 80)
}

/** Нормализует ASN/org/PTR/cloud-id в короткое имя хостера. */
export function canonicalizeHoster(raw: string | null | undefined): string | null {
  const value = raw?.replace(/\s+/g, ' ').trim()
  if (!value) return null
  const sliced = value.slice(0, 160)
  for (const alias of HOSTER_ALIASES) {
    if (alias.test.test(sliced)) return alias.name
  }
  return tidyOrgName(sliced)
}
