import type { Node, Edge } from '@xyflow/react'
import type { DeviceNodeData } from '@/components/network/nodes/DeviceNode'
import type { GroupNodeData } from '@/types/network-diagram'

// Maps our device slugs to draw.io Cisco stencil shape styles
const SLUG_TO_DRAWIO_STYLE: Record<string, string> = {
  'router':        'shape=mxgraph.cisco.routers.router;',
  'switch':        'shape=mxgraph.cisco.switches.layer_3_switch;',
  'access-point':  'shape=mxgraph.cisco.misc.access_point;',
  'load-balancer': 'shape=mxgraph.cisco.misc.generic_building;',
  'firewall':      'shape=mxgraph.cisco.firewalls.firewall;',
  'badge-reader':  'shape=mxgraph.cisco.misc.generic_building;',
  'server':        'shape=mxgraph.cisco.servers.standard_server;',
  'vm':            'shape=mxgraph.cisco.servers.standard_server;',
  'container':     'shape=mxgraph.cisco.servers.standard_server;',
  'nas':           'shape=mxgraph.cisco.storage.tape_storage_library;',
  'san':           'shape=mxgraph.cisco.storage.tape_storage_library;',
  'cloud-storage': 'shape=mxgraph.cisco.misc.cloud;',
  'cloud':         'shape=mxgraph.cisco.misc.cloud;',
  'aws':           'shape=mxgraph.cisco.misc.cloud;',
  'azure':         'shape=mxgraph.cisco.misc.cloud;',
  'gcp':           'shape=mxgraph.cisco.misc.cloud;',
  'isp':           'shape=mxgraph.cisco.misc.cloud;',
  'workstation':   'shape=mxgraph.cisco.computers_and_peripherals.pc;',
  'laptop':        'shape=mxgraph.cisco.computers_and_peripherals.laptop;',
  'tablet':        'shape=mxgraph.cisco.computers_and_peripherals.laptop;',
  'phone':         'shape=mxgraph.cisco.computers_and_peripherals.ip_phone;',
  'printer':       'shape=mxgraph.cisco.computers_and_peripherals.printer;',
  'ups':           'shape=mxgraph.cisco.misc.generic_building;',
  'pdu':           'shape=mxgraph.cisco.misc.generic_building;',
  'rack':          'shape=mxgraph.cisco.misc.generic_building;',
  'patch-panel':   'shape=mxgraph.cisco.misc.generic_building;',
  'camera':        'shape=mxgraph.cisco.misc.generic_building;',
  'nvr':           'shape=mxgraph.cisco.misc.generic_building;',
  'iot':           'shape=mxgraph.cisco.misc.generic_building;',
}

const BASE_NODE_STYLE =
  'sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;'
const GROUP_STYLE =
  'swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;collapsible=0;marginBottom=0;swimlaneHead=0;fillColor=none;'

function esc(s: string): string {
  return s
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
}

export function exportToDrawio(nodes: Node[], edges: Edge[]): string {
  const cells: string[] = [
    '<mxCell id="0"/>',
    '<mxCell id="1" parent="0"/>',
  ]

  for (const node of nodes) {
    const w = typeof node.style?.width === 'number' ? node.style.width : (node.measured?.width ?? 120)
    const h = typeof node.style?.height === 'number' ? node.style.height : (node.measured?.height ?? 120)
    const x = node.position.x
    const y = node.position.y
    const parentId = node.parentId ?? '1'

    if (node.type === 'group') {
      const gd = node.data as GroupNodeData
      cells.push(
        `<mxCell id="${esc(node.id)}" value="${esc(gd.label ?? '')}" style="${GROUP_STYLE}" vertex="1" parent="${esc(parentId)}">` +
        `<mxGeometry x="${x}" y="${y}" width="${w}" height="${h}" as="geometry"/>` +
        `</mxCell>`,
      )
    } else {
      const dd = node.data as DeviceNodeData
      const slug = dd.deviceType ?? 'server'
      const shapeStyle = SLUG_TO_DRAWIO_STYLE[slug] ?? 'rounded=1;whiteSpace=wrap;html=1;'
      cells.push(
        `<mxCell id="${esc(node.id)}" value="${esc(dd.label ?? '')}" style="${shapeStyle}${BASE_NODE_STYLE}" vertex="1" parent="${esc(parentId)}">` +
        `<mxGeometry x="${x}" y="${y}" width="${w}" height="${h}" as="geometry"/>` +
        `</mxCell>`,
      )
    }
  }

  for (const edge of edges) {
    const label = typeof edge.label === 'string' ? edge.label : ''
    cells.push(
      `<mxCell id="${esc(edge.id)}" value="${esc(label)}" style="edgeStyle=orthogonalEdgeStyle;html=1;" edge="1" source="${esc(edge.source)}" target="${esc(edge.target)}" parent="1">` +
      `<mxGeometry relative="1" as="geometry"/>` +
      `</mxCell>`,
    )
  }

  const xml =
    `<?xml version="1.0" encoding="UTF-8"?>\n` +
    `<mxGraphModel><root>\n` +
    cells.join('\n') +
    `\n</root></mxGraphModel>`

  return xml
}
