import type { DiagramNode, DiagramEdge } from '@/types/network-diagram'

// Maps draw.io shape identifiers (substrings of style) → our device slugs
const DRAWIO_SHAPE_TO_SLUG: Array<[string, string]> = [
  ['cisco.routers.router',                     'router'],
  ['cisco.routers',                             'router'],
  ['cisco.switches.layer_3_switch',             'switch'],
  ['cisco.switches.workgroup_switch',           'switch'],
  ['cisco.switches',                            'switch'],
  ['cisco.firewalls',                           'firewall'],
  ['cisco.servers',                             'server'],
  ['cisco.computers_and_peripherals.laptop',    'laptop'],
  ['cisco.computers_and_peripherals.ip_phone',  'phone'],
  ['cisco.computers_and_peripherals.pc',        'workstation'],
  ['cisco.computers_and_peripherals.printer',   'printer'],
  ['cisco.misc.access_point',                  'access-point'],
  ['cisco.misc.cloud',                         'cloud'],
  ['cisco.storage',                             'nas'],
  ['shape=router',                             'router'],
  ['shape=server',                             'server'],
  ['shape=firewall',                           'firewall'],
  ['shape=cloud',                              'cloud'],
]

function styleToSlug(style: string): string {
  const lower = style.toLowerCase()
  for (const [pattern, slug] of DRAWIO_SHAPE_TO_SLUG) {
    if (lower.includes(pattern)) return slug
  }
  return 'server'
}

function isGroup(style: string): boolean {
  return style.includes('swimlane') || style.includes('container') || style.includes('group')
}

export interface DrawioImportResult {
  nodes: DiagramNode[]
  edges: DiagramEdge[]
  warnings: string[]
}

export function parseDrawioXml(xmlString: string): DrawioImportResult {
  const parser = new DOMParser()
  const doc = parser.parseFromString(xmlString, 'application/xml')

  const parseError = doc.querySelector('parsererror')
  if (parseError) {
    throw new Error('Invalid draw.io XML: ' + parseError.textContent?.slice(0, 200))
  }

  const cells = Array.from(doc.querySelectorAll('mxCell'))
  const warnings: string[] = []
  const nodes: DiagramNode[] = []
  const edges: DiagramEdge[] = []

  const geoMap = new Map<string, { x: number; y: number; width: number; height: number }>()
  for (const cell of cells) {
    const geo = cell.querySelector('mxGeometry')
    if (geo) {
      geoMap.set(cell.getAttribute('id') ?? '', {
        x: parseFloat(geo.getAttribute('x') ?? '0'),
        y: parseFloat(geo.getAttribute('y') ?? '0'),
        width: parseFloat(geo.getAttribute('width') ?? '120'),
        height: parseFloat(geo.getAttribute('height') ?? '120'),
      })
    }
  }

  const groupIds = new Set<string>()

  for (const cell of cells) {
    const id = cell.getAttribute('id') ?? ''
    if (id === '0' || id === '1') continue

    const isEdge = cell.getAttribute('edge') === '1'
    const isVertex = cell.getAttribute('vertex') === '1'
    const style = cell.getAttribute('style') ?? ''
    const value = cell.getAttribute('value') ?? ''
    const parent = cell.getAttribute('parent') ?? '1'
    const geo = geoMap.get(id)

    if (isEdge) {
      const source = cell.getAttribute('source') ?? ''
      const target = cell.getAttribute('target') ?? ''
      if (!source || !target) {
        warnings.push(`Edge "${id}" skipped — missing source or target`)
        continue
      }
      edges.push({
        id,
        source,
        target,
        label: value || null,
        connectionType: 'ethernet',
        speed: null,
        notes: null,
        routing: null,
      })
      continue
    }

    if (isVertex && geo) {
      if (isGroup(style)) {
        groupIds.add(id)
        nodes.push({
          id,
          type: 'subnet',
          label: value || 'Group',
          position: { x: geo.x, y: geo.y },
          properties: {
            hostname: null, ip: null, subnet: null, vendor: null,
            model: null, role: null, vlan: null, notes: null, status: 'unknown',
          },
          nodeType: 'group',
          style: { width: geo.width, height: geo.height },
        })
      } else {
        const slug = styleToSlug(style)
        const parentId = parent !== '1' && groupIds.has(parent) ? parent : undefined
        nodes.push({
          id,
          type: slug,
          label: value || slug,
          position: { x: geo.x, y: geo.y },
          properties: {
            hostname: null, ip: null, subnet: null, vendor: null,
            model: null, role: null, vlan: null, notes: null, status: 'unknown',
          },
          ...(parentId ? { parentId } : {}),
          style: { width: geo.width, height: geo.height },
        })
      }
    }
  }

  if (nodes.length === 0) {
    warnings.push('No nodes were found in this draw.io file. Only basic shapes and Cisco stencil shapes are supported.')
  }

  return { nodes, edges, warnings }
}
