import { servers } from "@/lib/data"
import type { InterfaceType, PermLevel, AppUserRole as Role } from "@mmapp/contracts/users"

export type { InterfaceType, PermLevel, Role }

export interface SectionPerm { section: string; level: PermLevel }
export interface ServerPerm { serverId: string; level: PermLevel }

export interface InterfaceBinding {
  id: string
  userId: string
  serverId: string
  serverName: string
  serverSite: string
  serverCountry: string
  interfaceName: string
  interfaceType: InterfaceType
  peerPublicKey?: string
  peerName?: string
  comment: string
}

export interface CatalogPeer {
  publicKey: string
  name: string
  comment: string
  allowedIps: string[]
  latestHandshake?: string
  boundUserId: string | null
  boundUserLogin: string | null
}

export interface CatalogIface {
  name: string
  type: InterfaceType
  running: boolean
  disabled: boolean
  boundUserId: string | null
  boundUserLogin: string | null
  peers?: CatalogPeer[]
  peersError?: string
}

export interface AppUserForm {
  name: string
  login: string
  email: string
  role: Role
  active: boolean
  sections: SectionPerm[]
  servers: ServerPerm[]
  bindings: InterfaceBinding[]
}

export interface AppUser {
  id: string
  name: string
  login: string
  email: string
  role: Role
  last: string
  avatar: string
  active: boolean
  sections: SectionPerm[]
  servers: ServerPerm[]
  bindings: InterfaceBinding[]
}

export interface UserServerOption {
  id: string
  name: string
  host: string
  site: string
  country: string
  status?: "online" | "offline" | "degraded" | null
}

export const IFACE_TYPE_LABEL: Record<InterfaceType, string> = {
  ether: "Ethernet",
  gre: "GRE",
  wg: "WireGuard",
  other: "Прочие",
}

export const IFACE_TYPE_ORDER: InterfaceType[] = ["ether", "gre", "wg", "other"]

export const ROLE_LABEL: Record<Role, string> = {
  admin: "Администратор",
  operator: "Оператор",
  viewer: "Наблюдатель",
}

export const ROLE_COLOR: Record<Role, string> = {
  admin: "bg-violet-500/10 text-violet-600 dark:text-violet-400 border border-violet-500/20",
  operator: "bg-sky-500/10 text-sky-600 dark:text-sky-400 border border-sky-500/20",
  viewer: "bg-muted text-muted-foreground border border-border",
}

export const PERM_OPTS: { v: PermLevel; label: string }[] = [
  { v: "none", label: "Нет" },
  { v: "read", label: "Просмотр" },
  { v: "write", label: "Управление" },
]

export const PERM_COLOR: Record<PermLevel, string> = {
  none: "bg-muted text-muted-foreground",
  read: "bg-sky-500/10 text-sky-600 dark:text-sky-400",
  write: "bg-success/10 text-success",
}

export const SECTION_GROUP_DEFS: { group: string; items: string[] }[] = [
  { group: "Обзор", items: ["Дашборд", "Трафик", "Карта сети", "Мониторинг"] },
  { group: "Данные", items: ["Домены", "IP-диапазоны", "ASN", "Communities"] },
  { group: "Управление", items: ["Серверы", "Фильтры", "Firewall", "GRE-туннели", "Бэкапы"] },
  { group: "Инструменты", items: ["Оптимизатор маршрутов", "OSPF", "Диагностика GRE", "Терминал"] },
  { group: "Система", items: ["Оповещения", "Сбор данных", "Пользователи", "Настройки"] },
]

export const ALL_SECTIONS = SECTION_GROUP_DEFS.flatMap((g) => g.items)

export function defaultSections(role: Role): SectionPerm[] {
  return ALL_SECTIONS.map((section) => {
    let level: PermLevel = "none"
    if (role === "admin") level = "write"
    else if (role === "operator") {
      level = ["Серверы", "Пользователи", "Фильтры", "Firewall", "GRE-туннели", "Бэкапы", "Диагностика GRE", "Оптимизатор маршрутов", "OSPF"].includes(section)
        ? "write"
        : "read"
    } else if (role === "viewer") {
      level = ["Настройки", "Терминал"].includes(section) ? "none" : "read"
    }
    return { section, level }
  })
}

export function defaultServers(role: Role, serverList: { id: string }[] = servers): ServerPerm[] {
  return serverList.map((s) => ({
    serverId: s.id,
    level: role === "admin" ? "write" : "read",
  }))
}

export function userInitials(name: string): string {
  return name.trim().split(/\s+/).map((p) => p[0] ?? "").slice(0, 2).join("").toUpperCase() || "??"
}

export const MOCK_IFACE_CATALOG: Record<string, CatalogIface[]> = {
  srv1: [
    { name: "ether1", type: "ether", running: true, disabled: false, boundUserId: "u1", boundUserLogin: "a.korotaev@company.io" },
    { name: "ether2", type: "ether", running: true, disabled: false, boundUserId: null, boundUserLogin: null },
    { name: "gre-office-msk", type: "gre", running: true, disabled: false, boundUserId: "u1", boundUserLogin: "a.korotaev@company.io" },
    { name: "gre-datacenter", type: "gre", running: true, disabled: false, boundUserId: "u1", boundUserLogin: "a.korotaev@company.io" },
    { name: "gre-spb-branch", type: "gre", running: true, disabled: false, boundUserId: "u2", boundUserLogin: "d.fedorov@company.io" },
    { name: "gre-retail-01", type: "gre", running: false, disabled: false, boundUserId: "u4", boundUserLogin: "i.petrov@company.io" },
    {
      name: "wg-msk-spb", type: "wg", running: true, disabled: false, boundUserId: null, boundUserLogin: null,
      peers: [
        { publicKey: "mockPeerKeyAAAA0123456789", name: "phone-ak", comment: "", allowedIps: ["10.8.0.2/32"], boundUserId: "u1", boundUserLogin: "a.korotaev@company.io" },
        { publicKey: "mockPeerKeyBBBB0123456789", name: "laptop-ak", comment: "", allowedIps: ["10.8.0.3/32"], boundUserId: null, boundUserLogin: null, latestHandshake: "12s" },
      ],
    },
  ],
  srv7: [
    { name: "ether1", type: "ether", running: true, disabled: false, boundUserId: null, boundUserLogin: null },
    { name: "gre-office-msk", type: "gre", running: true, disabled: false, boundUserId: "u1", boundUserLogin: "a.korotaev@company.io" },
    { name: "gre-warehouse", type: "gre", running: false, disabled: false, boundUserId: "u1", boundUserLogin: "a.korotaev@company.io" },
    { name: "gre-spb-branch", type: "gre", running: true, disabled: false, boundUserId: "u2", boundUserLogin: "d.fedorov@company.io" },
    {
      name: "wg-lab", type: "wg", running: true, disabled: false, boundUserId: null, boundUserLogin: null,
      peers: [
        { publicKey: "mockPeerKeyLABB0123456789", name: "lab-peer", comment: "", allowedIps: ["10.9.0.2/32"], boundUserId: null, boundUserLogin: null },
      ],
    },
  ],
}

export function bindingDiffKey(b: Pick<InterfaceBinding, "serverId" | "interfaceName" | "peerPublicKey">): string {
  return `${b.serverId}::${b.interfaceName}::${b.peerPublicKey ?? ""}`
}

export function bindingTitle(b: Pick<InterfaceBinding, "interfaceName" | "interfaceType" | "peerName" | "peerPublicKey">): string {
  if (b.interfaceType === "wg" && (b.peerName || b.peerPublicKey)) {
    return `${b.peerName || "peer"} · ${b.interfaceName}`
  }
  return b.interfaceName
}

function bind(
  id: string,
  userId: string,
  serverId: string,
  interfaceName: string,
  interfaceType: InterfaceType,
  comment: string,
  peer?: { publicKey: string; name: string },
): InterfaceBinding {
  const srv = servers.find((s) => s.id === serverId)
  return {
    id,
    userId,
    serverId,
    serverName: srv?.name ?? serverId,
    serverSite: srv?.site ?? "—",
    serverCountry: srv?.country ?? "UN",
    interfaceName,
    interfaceType,
    peerPublicKey: peer?.publicKey,
    peerName: peer?.name,
    comment,
  }
}

export const INIT_USERS: AppUser[] = [
  {
    id: "u1", name: "Александр Коротаев", login: "a.korotaev@company.io", email: "a.korotaev@company.io",
    role: "admin", last: "сейчас", avatar: "АК", active: true,
    sections: defaultSections("admin"), servers: defaultServers("admin"),
    bindings: [
      bind("b1", "u1", "srv1", "ether1", "ether", "Uplink MSK"),
      bind("b2", "u1", "srv1", "gre-office-msk", "gre", "Офис MSK"),
      bind("b3", "u1", "srv1", "gre-datacenter", "gre", "ЦОД"),
      bind("b4", "u1", "srv1", "wg-msk-spb", "wg", "Overlay SPB", { publicKey: "mockPeerKeyAAAA0123456789", name: "phone-ak" }),
      bind("b5", "u1", "srv7", "gre-office-msk", "gre", "Офис LAB"),
      bind("b6", "u1", "srv7", "gre-warehouse", "gre", "Склад"),
    ],
  },
  {
    id: "u2", name: "Дмитрий Фёдоров", login: "d.fedorov@company.io", email: "d.fedorov@company.io",
    role: "operator", last: "2ч назад", avatar: "ДФ", active: true,
    sections: defaultSections("operator"), servers: defaultServers("operator"),
    bindings: [
      bind("b7", "u2", "srv1", "gre-spb-branch", "gre", "Филиал SPB"),
      bind("b8", "u2", "srv7", "gre-spb-branch", "gre", "Филиал LAB"),
    ],
  },
  {
    id: "u3", name: "Мария Соколова", login: "m.sokolova@company.io", email: "m.sokolova@company.io",
    role: "viewer", last: "вчера", avatar: "МС", active: true,
    sections: defaultSections("viewer"), servers: defaultServers("viewer"),
    bindings: [],
  },
  {
    id: "u4", name: "Игорь Петров", login: "i.petrov@company.io", email: "i.petrov@company.io",
    role: "operator", last: "3 дн назад", avatar: "ИП", active: false,
    sections: defaultSections("operator"), servers: defaultServers("operator"),
    bindings: [
      bind("b9", "u4", "srv1", "gre-retail-01", "gre", "Магазин #1"),
    ],
  },
]

export function catalogForServer(serverId: string, users: AppUser[]): CatalogIface[] {
  const base = MOCK_IFACE_CATALOG[serverId] ?? []
  return base.map((iface) => {
    if (iface.type === "wg") {
      const peers = (iface.peers ?? []).map((peer) => {
        const owner = users.find((u) =>
          u.bindings.some((b) =>
            b.serverId === serverId
            && b.interfaceName === iface.name
            && (b.peerPublicKey ?? "") === peer.publicKey,
          ),
        )
        if (!owner) return { ...peer, boundUserId: null, boundUserLogin: null }
        return { ...peer, boundUserId: owner.id, boundUserLogin: owner.email || owner.login }
      })
      const legacy = users.find((u) =>
        u.bindings.some((b) =>
          b.serverId === serverId
          && b.interfaceName === iface.name
          && !(b.peerPublicKey ?? ""),
        ),
      )
      return {
        ...iface,
        boundUserId: legacy?.id ?? null,
        boundUserLogin: legacy ? (legacy.email || legacy.login) : null,
        peers,
      }
    }
    const owner = users.find((u) =>
      u.bindings.some((b) => b.serverId === serverId && b.interfaceName === iface.name && !(b.peerPublicKey ?? "")),
    )
    if (!owner) return { ...iface, boundUserId: null, boundUserLogin: null }
    return { ...iface, boundUserId: owner.id, boundUserLogin: owner.email || owner.login }
  })
}

export function groupBindingsByServer(bindings: InterfaceBinding[]): Array<{
  serverId: string
  serverName: string
  serverSite: string
  serverCountry: string
  types: Array<{ type: InterfaceType; items: InterfaceBinding[] }>
}> {
  const byServer = new Map<string, InterfaceBinding[]>()
  for (const b of bindings) {
    const arr = byServer.get(b.serverId) ?? []
    arr.push(b)
    byServer.set(b.serverId, arr)
  }
  return [...byServer.entries()].map(([serverId, items]) => {
    const first = items[0]
    const types = IFACE_TYPE_ORDER
      .map((type) => ({ type, items: items.filter((i) => i.interfaceType === type) }))
      .filter((g) => g.items.length > 0)
    return {
      serverId,
      serverName: first?.serverName ?? serverId,
      serverSite: first?.serverSite ?? "—",
      serverCountry: first?.serverCountry ?? "UN",
      types,
    }
  })
}

export type UserAccessWriteKind = "full" | "none" | "partial"

export interface UserAccessSummary {
  sectionsGranted: number
  sectionsTotal: number
  serversGranted: number
  serversTotal: number
  writeKind: UserAccessWriteKind
  writeSections: string[]
}

export function summarizeUserAccess(
  user: Pick<AppUser, "role" | "sections" | "servers">,
  serversTotal: number,
  sectionsTotal = ALL_SECTIONS.length,
): UserAccessSummary {
  const isAdmin = user.role === "admin"
  const sectionsGranted = isAdmin
    ? sectionsTotal
    : user.sections.filter((s) => s.level !== "none").length
  const serversGranted = isAdmin
    ? serversTotal
    : user.servers.filter((s) => s.level !== "none").length
  const writeSections = isAdmin
    ? []
    : user.sections.filter((s) => s.level === "write").map((s) => s.section)
  const writeKind: UserAccessWriteKind = isAdmin
    ? "full"
    : writeSections.length === 0
      ? "none"
      : "partial"
  return {
    sectionsGranted,
    sectionsTotal,
    serversGranted,
    serversTotal,
    writeKind,
    writeSections,
  }
}
