import type { Node, Edge } from '@xyflow/react'
import type { NodeData, EdgeData, Waypoint } from '@/types'
import { normalizeHandle, clampBottomHandles } from '@/utils/handleUtils'

// ── Types ────────────────────────────────────────────────────────────────────

export interface ApiNode extends Record<string, unknown> {
  id: string
  type: string
  label: string
  pos_x: number
  pos_y: number
  status: string
  services: unknown[]
  hostname?: string | null
  ip?: string | null
  mac?: string | null
  os?: string | null
  check_method?: string | null
  check_target?: string | null
  notes?: string | null
  parent_id?: string | null
  container_mode?: boolean
  custom_colors?: Record<string, unknown> | null
  custom_icon?: string | null
  cpu_count?: number | null
  cpu_model?: string | null
  ram_gb?: number | null
  disk_gb?: number | null
  show_hardware?: boolean
  properties?: unknown[] | null
  width?: number | null
  height?: number | null
  bottom_handles?: number
}

export interface ApiEdge {
  id: string
  source: string
  target: string
  type: string
  label?: string | null
  vlan_id?: number | null
  speed?: string | null
  custom_color?: string | null
  path_style?: string | null
  animated?: boolean | 'snake' | 'flow' | 'basic' | 'none'
  source_handle?: string | null
  target_handle?: string | null
  waypoints?: Waypoint[] | null
}

// ── Serialization (RF node → API save payload) ───────────────────────────────

export function serializeNode(n: Node<NodeData>): Record<string, unknown> {
  if (n.data.type === 'groupRect') {
    return {
      id: n.id,
      type: 'groupRect',
      label: n.data.label,
      hostname: null,
      ip: null,
      mac: null,
      os: null,
      status: 'unknown',
      check_method: null,
      check_target: null,
      services: [],
      notes: null,
      parent_id: n.data.parent_id ?? null,
      container_mode: false,
      custom_icon: null,
      pos_x: n.position.x,
      pos_y: n.position.y,
      custom_colors: {
        ...n.data.custom_colors,
        width: n.measured?.width ?? n.width ?? 360,
        height: n.measured?.height ?? n.height ?? 240,
      },
    }
  }
  return {
    id: n.id,
    type: n.data.type,
    label: n.data.label,
    hostname: n.data.hostname ?? null,
    ip: n.data.ip ?? null,
    mac: n.data.mac ?? null,
    os: n.data.os ?? null,
    status: n.data.status,
    check_method: n.data.check_method ?? null,
    check_target: n.data.check_target ?? null,
    services: n.data.services ?? [],
    notes: n.data.notes ?? null,
    parent_id: n.data.parent_id ?? null,
    container_mode: n.data.container_mode ?? false,
    custom_colors: n.data.custom_colors ?? null,
    custom_icon: n.data.custom_icon ?? null,
    cpu_count: n.data.cpu_count ?? null,
    cpu_model: n.data.cpu_model ?? null,
    ram_gb: n.data.ram_gb ?? null,
    disk_gb: n.data.disk_gb ?? null,
    show_hardware: n.data.show_hardware ?? false,
    properties: n.data.properties ?? [],
    width: n.measured?.width ?? n.width ?? null,
    height: n.measured?.height ?? n.height ?? null,
    bottom_handles: clampBottomHandles(n.data.bottom_handles ?? 1),
    pos_x: n.position.x,
    pos_y: n.position.y,
  }
}

export function serializeEdge(e: Edge<EdgeData>): Record<string, unknown> {
  return {
    id: e.id,
    source: e.source,
    target: e.target,
    type: e.data?.type ?? 'ethernet',
    label: e.data?.label ?? null,
    vlan_id: e.data?.vlan_id ?? null,
    speed: e.data?.speed ?? null,
    custom_color: e.data?.custom_color ?? null,
    path_style: e.data?.path_style ?? null,
    animated: e.data?.animated ?? false,
    source_handle: normalizeHandle(e.sourceHandle),
    target_handle: normalizeHandle(e.targetHandle),
    waypoints: e.data?.waypoints?.length ? e.data.waypoints : null,
  }
}

// ── Deserialization (API response → RF node/edge) ────────────────────────────

export function deserializeApiNode(
  n: ApiNode,
  proxmoxContainerMap: Map<string, boolean>,
): Node<NodeData> {
  const normalizedType = n.type === 'docker' ? 'docker_host' : n.type
  if (n.type === 'groupRect') {
    const w = (n.custom_colors?.width as number | undefined) ?? 360
    const h = (n.custom_colors?.height as number | undefined) ?? 240
    const z = (n.custom_colors?.z_order as number | undefined) ?? 1
    return {
      id: n.id,
      type: 'groupRect',
      position: { x: n.pos_x, y: n.pos_y },
      data: n as unknown as NodeData,
      width: w,
      height: h,
      zIndex: z - 10,
      ...(n.parent_id ? { parentId: n.parent_id, extent: 'parent' as const } : {}),
    }
  }
  const parentIsContainer = n.parent_id ? (proxmoxContainerMap.get(n.parent_id) ?? false) : false
  return {
    id: n.id,
    type: normalizedType,
    position: { x: n.pos_x, y: n.pos_y },
    data: { ...n, type: normalizedType, bottom_handles: clampBottomHandles(n.bottom_handles ?? 1) } as unknown as NodeData,
    ...(n.parent_id && parentIsContainer ? { parentId: n.parent_id, extent: 'parent' as const } : {}),
    ...(['proxmox', 'vm', 'lxc', 'docker_host'].includes(normalizedType) && n.container_mode !== false
      ? { width: n.width ?? 300, height: n.height ?? 200 }
      : {}),
    ...(n.width && !['proxmox', 'vm', 'lxc', 'docker_host'].includes(normalizedType) ? { width: n.width } : {}),
    ...(n.height && !['proxmox', 'vm', 'lxc', 'docker_host'].includes(normalizedType) ? { height: n.height } : {}),
  }
}

export function deserializeApiEdge(e: ApiEdge): Edge<EdgeData> {
  return {
    id: e.id,
    source: e.source,
    target: e.target,
    type: e.type,
    sourceHandle: e.source_handle ?? null,
    targetHandle: e.target_handle ?? null,
    data: e as unknown as EdgeData,
  }
}
