import { useCallback } from 'react'
import { jsPDF } from 'jspdf'
import type { DrawFeature, Project } from '@/types'

interface UseMapExportOptions {
  mapRef: React.MutableRefObject<any>
  featuresRef: React.MutableRefObject<DrawFeature[]>
  currentProject: Project | null
  tenant: { id: string; name: string } | null
  addAudit: (action: string) => void
  toast: (opts: { title: string; description?: string; variant?: string }) => void
}

export function useMapExport({
  mapRef,
  featuresRef,
  currentProject,
  tenant,
  addAudit,
  toast,
}: UseMapExportOptions) {
  const handleExport = useCallback(async (format: 'png' | 'pdf') => {
    const mapInstance = mapRef.current
    if (!mapInstance) {
      toast({ title: 'Fehler', description: 'Karte nicht bereit.', variant: 'destructive' })
      return
    }

    try {
      // 1. Get the MapLibre canvas (tiles + vector drawings)
      const mapCanvas = mapInstance.getCanvas() as HTMLCanvasElement
      const w = mapCanvas.width
      const h = mapCanvas.height

      // 2. Create composite canvas
      const exportCanvas = document.createElement('canvas')
      exportCanvas.width = w
      exportCanvas.height = h
      const ctx = exportCanvas.getContext('2d')!
      ctx.drawImage(mapCanvas, 0, 0)

      // 3. Draw symbols manually at correct size/rotation
      const currentFeatures = featuresRef.current
      // Derive actual pixel ratio from canvas vs container (more reliable than window.devicePixelRatio)
      const container = mapInstance.getContainer()
      const dpr = mapCanvas.width / container.offsetWidth
      const zoom = mapInstance.getZoom()
      // Symbol sizing: match the map rendering logic exactly
      // In map-view.tsx: size = baseSize * scale * Math.pow(2, currentZoom - placementZoom)
      const currentZoom = zoom

      // Helper: load image as promise
      const loadImage = (src: string): Promise<HTMLImageElement> => new Promise((resolve, reject) => {
        const img = new Image()
        img.crossOrigin = 'anonymous'
        img.onload = () => resolve(img)
        img.onerror = reject
        img.src = src
      })

      // Draw symbol features
      for (const f of currentFeatures.filter(f => f.type === 'symbol')) {
        if (f.geometry.type !== 'Point') continue
        const coords = f.geometry.coordinates as [number, number]
        const pixel = mapInstance.project(coords)
        const px = pixel.x * dpr
        const py = pixel.y * dpr

        const scale = (f.properties.scale as number) || 1
        const rotation = (f.properties.rotation as number) || 0
        const baseSize = 32
        const placementZoom = (f.properties.placementZoom as number) || 17
        const zoomFactor = Math.pow(2, currentZoom - placementZoom)
        const size = Math.max(8, Math.min(400, baseSize * scale * zoomFactor)) * dpr

        // Determine image source
        const iconId = f.properties.iconId as string
        const imageUrl = f.properties.imageUrl as string
        let imgSrc = imageUrl || ''
        if (!imgSrc && iconId) {
          const { getSymbolById, getSymbolDataUri } = await import('@/lib/fw-symbols')
          const sym = getSymbolById(iconId)
          if (sym) imgSrc = getSymbolDataUri(sym)
        }

        if (imgSrc) {
          try {
            const img = await loadImage(imgSrc)
            // Replicate CSS background-size: contain (preserve aspect ratio)
            const imgAspect = img.naturalWidth / img.naturalHeight
            let drawW = size
            let drawH = size
            if (imgAspect > 1) {
              drawH = size / imgAspect
            } else {
              drawW = size * imgAspect
            }
            ctx.save()
            ctx.translate(px, py)
            ctx.rotate((rotation * Math.PI) / 180)
            ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH)
            ctx.restore()
          } catch (e) {
            console.warn('[Export] Failed to load symbol image:', iconId, e)
          }
        }
      }

      // Draw arrowheads for arrow features
      for (const f of currentFeatures.filter(f => f.type === 'arrow')) {
        if (f.geometry.type !== 'LineString') continue
        const lineCoords = f.geometry.coordinates as number[][]
        if (lineCoords.length < 2) continue
        const p1 = lineCoords[lineCoords.length - 2]
        const p2 = lineCoords[lineCoords.length - 1]
        const px1 = mapInstance.project(p1 as [number, number])
        const px2 = mapInstance.project(p2 as [number, number])
        const angle = Math.atan2(px2.y - px1.y, px2.x - px1.x)
        const color = (f.properties.color as string) || '#000000'
        const arrowSize = 14 * dpr

        ctx.save()
        ctx.translate(px2.x * dpr, px2.y * dpr)
        ctx.rotate(angle + Math.PI / 2)
        ctx.beginPath()
        ctx.moveTo(0, -arrowSize)
        ctx.lineTo(-arrowSize * 0.7, arrowSize * 0.3)
        ctx.lineTo(arrowSize * 0.7, arrowSize * 0.3)
        ctx.closePath()
        ctx.fillStyle = color
        ctx.fill()
        ctx.restore()
      }

      // Draw line/polygon label markers at midpoints
      for (const f of currentFeatures.filter(f => f.properties.label && (f.geometry.type === 'LineString' || f.geometry.type === 'Polygon'))) {
        const label = f.properties.label as string
        let midpoint: [number, number]

        if (f.geometry.type === 'LineString') {
          const coords = f.geometry.coordinates as number[][]
          const midIdx = Math.floor(coords.length / 2)
          if (coords.length === 2) {
            midpoint = [(coords[0][0] + coords[1][0]) / 2, (coords[0][1] + coords[1][1]) / 2]
          } else {
            midpoint = coords[midIdx] as [number, number]
          }
        } else {
          // Polygon: centroid of first ring
          const ring = (f.geometry.coordinates as number[][][])[0]
          const len = ring.length - 1
          let cx = 0, cy = 0
          for (let i = 0; i < len; i++) { cx += ring[i][0]; cy += ring[i][1] }
          midpoint = [cx / len, cy / len]
        }

        const pixel = mapInstance.project(midpoint)
        const px = pixel.x * dpr
        const py = pixel.y * dpr
        const fontSize = 13 * dpr
        const isDanger = f.type === 'dangerzone'
        const bgColor = isDanger ? 'rgba(220,38,38,0.85)' : 'rgba(0,0,0,0.75)'
        const borderColor = isDanger ? '#dc2626' : 'rgba(255,255,255,0.5)'

        ctx.save()
        ctx.font = `bold ${fontSize}px system-ui, sans-serif`
        ctx.textAlign = 'center'
        ctx.textBaseline = 'middle'
        const metrics = ctx.measureText(label)
        const padX = 7 * dpr
        const padY = 3 * dpr
        const boxW = metrics.width + padX * 2
        const boxH = fontSize + padY * 2
        const radius = 4 * dpr

        // Background pill
        ctx.fillStyle = bgColor
        ctx.beginPath()
        ctx.roundRect(px - boxW / 2, py - boxH / 2, boxW, boxH, radius)
        ctx.fill()

        // Border
        ctx.strokeStyle = borderColor
        ctx.lineWidth = 1.5 * dpr
        ctx.beginPath()
        ctx.roundRect(px - boxW / 2, py - boxH / 2, boxW, boxH, radius)
        ctx.stroke()

        // Text
        ctx.fillStyle = '#ffffff'
        ctx.fillText(label, px, py)
        ctx.restore()
      }

      // Draw text features
      for (const f of currentFeatures.filter(f => f.type === 'text')) {
        if (f.geometry.type !== 'Point') continue
        const coords = f.geometry.coordinates as [number, number]
        const pixel = mapInstance.project(coords)
        const px = pixel.x * dpr
        const py = pixel.y * dpr

        const text = (f.properties.text as string) || ''
        const fontSize = ((f.properties.fontSize as number) || 14) * dpr
        const color = (f.properties.color as string) || '#000000'

        ctx.save()
        ctx.font = `bold ${fontSize}px system-ui, sans-serif`
        ctx.textAlign = 'center'
        ctx.textBaseline = 'middle'
        // White outline
        ctx.strokeStyle = '#ffffff'
        ctx.lineWidth = 3 * dpr
        ctx.lineJoin = 'round'
        ctx.strokeText(text, px, py)
        // Fill
        ctx.fillStyle = color
        ctx.fillText(text, px, py)
        ctx.restore()
      }

      // ── Nordpfeil + Massstab + Wind in die Karte einbrennen (PNG & PDF) ──
      const bearing = mapInstance.getBearing() || 0

      // Massstabsbalken (unten links): meter/CSS-Pixel aus zwei entprojizierten Punkten
      const hav = (a: [number, number], b: [number, number]) => {
        const R = 6371000, toR = Math.PI / 180
        const dLat = (b[1] - a[1]) * toR, dLng = (b[0] - a[0]) * toR
        const s = Math.sin(dLat / 2) ** 2 + Math.cos(a[1] * toR) * Math.cos(b[1] * toR) * Math.sin(dLng / 2) ** 2
        return 2 * R * Math.atan2(Math.sqrt(s), Math.sqrt(1 - s))
      }
      try {
        const midY = container.offsetHeight / 2
        const pA = mapInstance.unproject([0, midY]); const pB = mapInstance.unproject([100, midY])
        const mPerCss = hav([pA.lng, pA.lat], [pB.lng, pB.lat]) / 100
        const nice = [5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 5000]
        const raw = mPerCss * 120
        const niceM = nice.reduce((p, c) => Math.abs(c - raw) < Math.abs(p - raw) ? c : p, nice[0])
        const barPx = (niceM / mPerCss) * dpr
        const bx = 18 * dpr, by = h - 26 * dpr
        ctx.save()
        ctx.strokeStyle = '#111'; ctx.fillStyle = '#111'; ctx.lineWidth = 3 * dpr
        ctx.beginPath(); ctx.moveTo(bx, by); ctx.lineTo(bx + barPx, by)
        ctx.moveTo(bx, by - 5 * dpr); ctx.lineTo(bx, by + 5 * dpr)
        ctx.moveTo(bx + barPx, by - 5 * dpr); ctx.lineTo(bx + barPx, by + 5 * dpr); ctx.stroke()
        ctx.font = `bold ${11 * dpr}px system-ui, sans-serif`; ctx.textAlign = 'left'; ctx.textBaseline = 'bottom'
        const label = niceM >= 1000 ? `${niceM / 1000} km` : `${niceM} m`
        ctx.lineWidth = 3 * dpr; ctx.strokeStyle = '#fff'; ctx.strokeText(label, bx, by - 6 * dpr)
        ctx.fillText(label, bx, by - 6 * dpr)
        ctx.restore()
      } catch { /* Massstab optional */ }

      // Nordpfeil (oben rechts), dreht mit dem Bearing
      {
        const cx = w - 34 * dpr, cy = 34 * dpr, r = 22 * dpr
        ctx.save()
        ctx.translate(cx, cy)
        ctx.beginPath(); ctx.arc(0, 0, r, 0, Math.PI * 2)
        ctx.fillStyle = 'rgba(255,255,255,0.92)'; ctx.fill()
        ctx.strokeStyle = 'rgba(0,0,0,0.15)'; ctx.lineWidth = 1 * dpr; ctx.stroke()
        ctx.rotate((-bearing * Math.PI) / 180)
        ctx.beginPath(); ctx.moveTo(0, -r * 0.7); ctx.lineTo(r * 0.28, r * 0.15); ctx.lineTo(0, 0); ctx.lineTo(-r * 0.28, r * 0.15); ctx.closePath()
        ctx.fillStyle = '#dc2626'; ctx.fill()
        ctx.beginPath(); ctx.moveTo(0, r * 0.7); ctx.lineTo(r * 0.28, -r * 0.15); ctx.lineTo(0, 0); ctx.lineTo(-r * 0.28, -r * 0.15); ctx.closePath()
        ctx.fillStyle = '#9ca3af'; ctx.fill()
        ctx.rotate((bearing * Math.PI) / 180) // Label aufrecht
        ctx.font = `bold ${11 * dpr}px system-ui, sans-serif`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'
        ctx.fillStyle = '#dc2626'; ctx.fillText('N', 0, -r - 7 * dpr)
        ctx.restore()
      }

      // Windrichtung (unter dem Nordpfeil), falls gesetzt
      const windDir = currentProject?.windDirection
      if (typeof windDir === 'number') {
        const dirs = ['N', 'NO', 'O', 'SO', 'S', 'SW', 'W', 'NW']
        const label = `Wind aus ${dirs[Math.round(((windDir % 360) + 360) % 360 / 45) % 8]}`
        const cx = w - 34 * dpr, cy = 70 * dpr
        ctx.save()
        ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`; ctx.textAlign = 'center'
        const tw = ctx.measureText(label).width
        const padX = 7 * dpr, boxW = tw + 20 * dpr + padX * 2, boxH = 18 * dpr
        ctx.fillStyle = '#2563eb'
        ctx.beginPath(); ctx.roundRect(cx - boxW / 2, cy - boxH / 2, boxW, boxH, 9 * dpr); ctx.fill()
        // Drift-Pfeil (wohin es weht)
        ctx.save()
        ctx.translate(cx - boxW / 2 + 11 * dpr, cy)
        ctx.rotate(((windDir + 180 - bearing) * Math.PI) / 180)
        ctx.beginPath(); ctx.moveTo(0, -6 * dpr); ctx.lineTo(4 * dpr, 5 * dpr); ctx.lineTo(0, 2.5 * dpr); ctx.lineTo(-4 * dpr, 5 * dpr); ctx.closePath()
        ctx.fillStyle = '#fff'; ctx.fill()
        ctx.restore()
        ctx.fillStyle = '#fff'; ctx.textBaseline = 'middle'
        ctx.fillText(label, cx + 8 * dpr, cy)
        ctx.restore()
      }

      const title = currentProject?.title || 'Lageplan'
      const safeName = title.replace(/[^a-z0-9äöüÄÖÜß]/gi, '_')

      // Distinkte Symbole für die PDF-Legende (nur solche mit Bild)
      const distinctSymbols: { iconId: string; imageUrl: string }[] = []
      const seenIcon = new Set<string>()
      for (const f of currentFeatures) {
        if (f.type !== 'symbol') continue
        const imageUrl = (f.properties.imageUrl as string) || ''
        const iconId = (f.properties.iconId as string) || imageUrl
        if (!imageUrl || seenIcon.has(iconId)) continue
        seenIcon.add(iconId)
        distinctSymbols.push({ iconId: (f.properties.iconId as string) || '', imageUrl })
      }

      if (format === 'png') {
        const link = document.createElement('a')
        link.download = `${safeName}.png`
        link.href = exportCanvas.toDataURL('image/png')
        link.click()
        addAudit(`Export: ${safeName}.png`)
        toast({ title: 'Exportiert', description: `${safeName}.png wurde heruntergeladen.` })
      } else {
        // PDF Export — rapport-style clean layout
        const imgData = exportCanvas.toDataURL('image/png')
        const now = new Date()
        const dateStr = now.toLocaleDateString('de-CH', { day: '2-digit', month: '2-digit', year: 'numeric' })
        const timeStr = now.toLocaleTimeString('de-CH', { hour: '2-digit', minute: '2-digit' })
        const locationStr = currentProject?.location || ''
        const einsatzNr = (currentProject as any)?.einsatzNr || ''
        const tenantLabel = tenant?.name || ''

        // A4 landscape (mm)
        const pdf = new jsPDF('l', 'mm', 'a4')
        const pageW = pdf.internal.pageSize.getWidth()   // 297
        const pageH = pdf.internal.pageSize.getHeight()   // 210
        const m = 10 // margin

        // ── Header section ──
        const headerY = m
        pdf.setFontSize(18)
        pdf.setFont('helvetica', 'bold')
        pdf.setTextColor(26, 26, 26)
        pdf.text('Einsatz-Lageplan', m, headerY + 6)

        pdf.setFontSize(9)
        pdf.setFont('helvetica', 'normal')
        pdf.setTextColor(107, 114, 128) // gray-500
        pdf.text(`${tenantLabel}${tenantLabel ? '  ·  ' : ''}${title}`, m, headerY + 12)

        // Right side: Einsatz-Nr + date
        pdf.setFontSize(14)
        pdf.setFont('helvetica', 'bold')
        pdf.setTextColor(185, 28, 28) // red-700
        if (einsatzNr) {
          const nrW = pdf.getTextWidth(einsatzNr)
          pdf.text(einsatzNr, pageW - m - nrW, headerY + 6)
        }
        pdf.setFontSize(9)
        pdf.setFont('helvetica', 'normal')
        pdf.setTextColor(107, 114, 128)
        const dateLabel = `${dateStr}  ·  ${timeStr}`
        const dlW = pdf.getTextWidth(dateLabel)
        pdf.text(dateLabel, pageW - m - dlW, headerY + 12)

        // Divider line + red accent
        const divY = headerY + 15
        pdf.setDrawColor(26, 26, 26)
        pdf.setLineWidth(0.8)
        pdf.line(m, divY, pageW - m, divY)
        pdf.setFillColor(185, 28, 28)
        pdf.rect(m, divY, (pageW - 2 * m) * 0.3, 1, 'F')

        // ── Map image ──
        const legendH = distinctSymbols.length > 0 ? 16 : 0
        const mapTop = divY + 3
        const mapBottom = pageH - m - 12 - legendH // Platz für Fusszeile (+ Legende)
        const mapAreaW = pageW - 2 * m
        const mapAreaH = mapBottom - mapTop

        // Fit map image into area while preserving aspect ratio
        const imgAspect = w / h
        const areaAspect = mapAreaW / mapAreaH
        let drawW = mapAreaW
        let drawH = mapAreaH
        if (imgAspect > areaAspect) {
          drawH = mapAreaW / imgAspect
        } else {
          drawW = mapAreaH * imgAspect
        }
        const mapX = m + (mapAreaW - drawW) / 2
        const mapY = mapTop + (mapAreaH - drawH) / 2

        // Light border around map
        pdf.setDrawColor(229, 231, 235)
        pdf.setLineWidth(0.3)
        pdf.rect(mapX, mapY, drawW, drawH)
        pdf.addImage(imgData, 'PNG', mapX, mapY, drawW, drawH)

        // ── Legende (verwendete Symbole) ──
        if (legendH > 0) {
          // Namen aus /api/icons beziehen (id → name)
          const nameMap: Record<string, string> = {}
          try {
            const r = await fetch('/api/icons')
            if (r.ok) {
              const d = await r.json()
              ;(d.categories || []).forEach((c: any) => (c.icons || []).forEach((ic: any) => { nameMap[ic.id] = ic.name }))
              ;(d.tenantSymbolGroups || []).forEach((g: any) => (g.symbols || []).forEach((s: any) => { nameMap[s.id] = s.name }))
            }
          } catch { /* Namen optional */ }

          const legY = mapBottom + 4
          pdf.setFontSize(7); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(107, 114, 128)
          pdf.text('LEGENDE', m, legY - 1)
          pdf.setFont('helvetica', 'normal'); pdf.setTextColor(40, 40, 40)
          let lx = m, ly = legY + 1
          for (const s of distinctSymbols.slice(0, 16)) {
            try {
              const img = await loadImage(s.imageUrl)
              const c = document.createElement('canvas'); c.width = 48; c.height = 48
              const cctx = c.getContext('2d')!; cctx.drawImage(img, 0, 0, 48, 48)
              pdf.addImage(c.toDataURL('image/png'), 'PNG', lx, ly, 5, 5)
            } catch { /* Symbolbild optional */ }
            const name = (nameMap[s.iconId] || '').slice(0, 22)
            pdf.text(name, lx + 6, ly + 3.5)
            const nameW = Math.min(34, pdf.getTextWidth(name) + 3)
            lx += 6 + nameW + 5
            if (lx > pageW - m - 40) { lx = m; ly += 6.5 }
          }
          if (distinctSymbols.length > 16) {
            pdf.setTextColor(150, 150, 150)
            pdf.text(`+${distinctSymbols.length - 16} weitere`, lx, ly + 3.5)
          }
        }

        // ── Footer ──
        const footerY = pageH - m - 4
        pdf.setFontSize(7)
        pdf.setFont('helvetica', 'normal')
        pdf.setTextColor(156, 163, 175) // gray-400
        pdf.text(`Erstellt: ${dateStr} ${timeStr}${locationStr ? '  ·  Standort: ' + locationStr : ''}  ·  Projekt: ${title}`, m, footerY)
        const footerR = 'app.lageplan.ch'
        const frW = pdf.getTextWidth(footerR)
        pdf.text(footerR, pageW - m - frW, footerY)

        pdf.save(`${safeName}.pdf`)
        addAudit(`Export: ${safeName}.pdf`)
        toast({ title: 'Exportiert', description: `${safeName}.pdf wurde heruntergeladen.` })
      }
    } catch (error) {
      console.error('Export error:', error)
      toast({ title: 'Fehler', description: 'Export fehlgeschlagen.', variant: 'destructive' })
    }
  }, [currentProject, tenant, toast, addAudit, mapRef, featuresRef])

  return { handleExport }
}
