import { useEffect, useRef, useCallback, type CSSProperties } from 'react'
import BpmnViewer from 'bpmn-js/lib/Viewer'
import { Maximize2, ZoomIn, ZoomOut } from 'lucide-react'

const ZOOM_STEP = 1.2
const ZOOM_MIN = 0.1
const ZOOM_MAX = 4

export type BpmnElementCategory = 'activity' | 'gateway' | 'other'

const ACTIVITY_TYPES = new Set([
  'bpmn:Task', 'bpmn:UserTask', 'bpmn:ServiceTask', 'bpmn:ScriptTask',
  'bpmn:ManualTask', 'bpmn:BusinessRuleTask', 'bpmn:SubProcess',
])

const GATEWAY_TYPES = new Set([
  'bpmn:ExclusiveGateway', 'bpmn:ParallelGateway',
  'bpmn:InclusiveGateway', 'bpmn:EventBasedGateway',
])

function classifyElement(type: string): BpmnElementCategory {
  if (ACTIVITY_TYPES.has(type)) return 'activity'
  if (GATEWAY_TYPES.has(type)) return 'gateway'
  return 'other'
}

// Badge de automatización — identidad InQ naranja sólido (Etapa 9 Sprint 1.5).
// Usa var(--inq-orange) definido en globals.css :root para consistencia con el sistema de design.
// Emoji ⚡ como símbolo provisional — reemplazo por <Bot /> agendado Sprint 2-3.
function makeBadgeHtml(): string {
  return `<div class="automatable-badge" title="Actividad marcada como automatizable" style="
    width:20px;height:20px;
    border-radius:50%;
    background:var(--inq-orange);
    border:1.5px solid white;
    box-shadow:0 1px 2px rgba(0,0,0,0.10);
    display:flex;align-items:center;justify-content:center;
    color:white;
    font-size:11px;font-weight:700;
    line-height:20px;
    cursor:default;
    pointer-events:none;
    z-index:10;
  ">⚡</div>`
}

// Identificador del tipo de overlay para poder remover solo los nuestros.
const OVERLAY_TYPE = 'automation-indicator'

interface BpmnCanvasProps {
  xml: string
  onElementClick?: (elementId: string, elementName: string, category: BpmnElementCategory) => void
  selectedElementId?: string | null
  automatableElementIds?: string[]  // IDs de actividades marcadas como automatizables
  className?: string
}

export function BpmnCanvas({
  xml,
  onElementClick,
  selectedElementId,
  automatableElementIds = [],
  className,
}: BpmnCanvasProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const viewerRef = useRef<InstanceType<typeof BpmnViewer> | null>(null)
  const isImportedRef = useRef(false)

  // ─── Inicializar viewer ────────────────────────────────────────────────────
  useEffect(() => {
    if (!containerRef.current) return
    const viewer = new BpmnViewer({ container: containerRef.current })
    viewerRef.current = viewer
    return () => {
      isImportedRef.current = false
      viewer.destroy()
      viewerRef.current = null
    }
  }, [])

  // ─── Sincronizar overlays de automatización ───────────────────────────────
  const syncAutomationOverlays = useCallback(() => {
    const viewer = viewerRef.current
    if (!viewer || !isImportedRef.current) return

    const overlays = viewer.get('overlays') as any
    const reg = viewer.get('elementRegistry') as any

    // Remover overlays anteriores del tipo propio antes de re-agregar
    overlays.remove({ type: OVERLAY_TYPE })

    for (const elementId of automatableElementIds) {
      try {
        // Leer el ancho real del elemento para posicionar el badge en la
        // esquina superior derecha con overlap: left = width - 12 pone el
        // borde derecho del badge 8px fuera del borde derecho del nodo.
        // (right: -8 en la API tiene semántica distinta: left = -right + width
        //  con -8 daría left = 8 + width, enteramente fuera del nodo.)
        const el = reg?.get(elementId)
        const width = el?.width ?? 100
        overlays.add(elementId, OVERLAY_TYPE, {
          position: { top: -8, left: width - 12 },
          html: makeBadgeHtml(),
        })
      } catch {
        // El elemento puede no existir en el diagrama actual — ignorar
      }
    }
  }, [automatableElementIds])

  // ─── Importar XML ──────────────────────────────────────────────────────────
  useEffect(() => {
    const viewer = viewerRef.current
    if (!viewer || !xml) return
    isImportedRef.current = false
    viewer.importXML(xml).then(({ warnings }) => {
      // Si el viewer fue destruido y reemplazado (p.ej. React Strict Mode), ignorar
      if (viewerRef.current !== viewer) return
      if (warnings.length) console.warn('bpmn-js warnings:', warnings)
      const canvas = viewer.get('canvas') as any
      canvas.zoom('fit-viewport', 'auto')
      isImportedRef.current = true
      syncAutomationOverlays()
    }).catch((err: Error) => {
      if (viewerRef.current !== viewer) return
      console.error('Error cargando BPMN:', err)
    })
  }, [xml, syncAutomationOverlays])

  // ─── Re-sincronizar overlays cuando cambia la lista de automatizables ─────
  useEffect(() => {
    syncAutomationOverlays()
  }, [syncAutomationOverlays])

  // ─── Click handler ─────────────────────────────────────────────────────────
  useEffect(() => {
    const viewer = viewerRef.current
    if (!viewer || !onElementClick) return
    const eventBus = viewer.get('eventBus') as any

    const handler = (event: any) => {
      const el = event.element
      if (!el) return
      const category = classifyElement(el.type)
      if (category === 'other') return
      onElementClick(el.id, el.businessObject?.name ?? el.id, category)
    }

    eventBus.on('element.click', handler)
    return () => eventBus.off('element.click', handler)
  }, [onElementClick])

  // ─── Highlight del elemento seleccionado ──────────────────────────────────
  useEffect(() => {
    const viewer = viewerRef.current
    if (!viewer) return
    const canvas = viewer.get('canvas') as any
    const reg = viewer.get('elementRegistry') as any
    reg.forEach((el: any) => canvas.removeMarker(el.id, 'bpmn-selected'))
    if (selectedElementId) {
      try { canvas.addMarker(selectedElementId, 'bpmn-selected') } catch { /* ignorar */ }
    }
  }, [selectedElementId])

  function handleZoomIn() {
    const canvas = viewerRef.current?.get('canvas') as any
    if (!canvas) return
    canvas.zoom(Math.min(canvas.zoom() * ZOOM_STEP, ZOOM_MAX))
  }

  function handleZoomOut() {
    const canvas = viewerRef.current?.get('canvas') as any
    if (!canvas) return
    canvas.zoom(Math.max(canvas.zoom() / ZOOM_STEP, ZOOM_MIN))
  }

  const controlButtonStyle: CSSProperties = {
    width: 32,
    height: 32,
    borderRadius: 6,
    background: 'hsl(var(--background))',
    border: '1px solid hsl(var(--border))',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    cursor: 'pointer',
    boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
  }

  return (
    <div className={className} style={{ position: 'relative', width: '100%', height: '100%' }}>
      <div ref={containerRef} style={{ width: '100%', height: '100%' }} />

      {/* Encuadrar — esquina superior derecha */}
      <button
        onClick={() => {
          const canvas = viewerRef.current?.get('canvas') as any
          canvas?.zoom('fit-viewport', 'auto')
        }}
        title="Encuadrar diagrama"
        style={{ position: 'absolute', top: 12, right: 12, zIndex: 10, ...controlButtonStyle }}
      >
        <Maximize2 className="h-4 w-4 text-muted-foreground" />
      </button>

      {/* Zoom in/out — esquina inferior derecha, no interfiere con el botón de encuadre */}
      <div style={{ position: 'absolute', bottom: 12, left: 12, zIndex: 10, display: 'flex', flexDirection: 'column', gap: 4 }}>
        <button onClick={handleZoomIn} title="Acercar" style={controlButtonStyle}>
          <ZoomIn className="h-4 w-4 text-muted-foreground" />
        </button>
        <button onClick={handleZoomOut} title="Alejar" style={controlButtonStyle}>
          <ZoomOut className="h-4 w-4 text-muted-foreground" />
        </button>
      </div>
    </div>
  )
}
