<template>
  <div class="shopfloor-map">
    <!-- Controls for legacy machine mode only (MapView handles filters for asset mode) -->
    <div class="map-controls" v-if="!pickerMode && !assetTypeMode">
      <div class="filters">
        <select v-model="filters.machinetype" @change="applyFilters">
          <option value="">All Types</option>
          <option v-for="t in machinetypes" :key="t.machinetypeid" :value="t.machinetypeid">
            {{ t.machinetype }}
          </option>
        </select>

        <select v-model="filters.businessunit" @change="applyFilters">
          <option value="">All Business Units</option>
          <option v-for="bu in businessunits" :key="bu.businessunitid" :value="bu.businessunitid">
            {{ bu.businessunit }}
          </option>
        </select>

        <select v-model="filters.status" @change="applyFilters">
          <option value="">All Statuses</option>
          <option v-for="s in statuses" :key="s.statusid" :value="s.statusid">
            {{ s.status }}
          </option>
        </select>

        <input
          type="text"
          v-model="filters.search"
          placeholder="Search..."
          @input="debounceSearch"
        />
      </div>

      <div class="legend">
        <span
          v-for="t in visibleTypes"
          :key="t.machinetypeid"
          class="legend-item"
        >
          <span class="legend-dot" :style="{ background: getTypeColor(t.machinetype) }"></span>
          {{ t.machinetype }}
        </span>
      </div>
    </div>

    <!-- Legend for asset type mode - shows subtypes when a type is selected -->
    <div class="map-legend" v-if="!pickerMode && assetTypeMode">
      <!-- Show subtype legend when a specific type is selected -->
      <template v-if="selectedAssetType && Object.keys(visibleSubtypes).length">
        <span
          v-for="(color, subtypeId) in visibleSubtypes"
          :key="subtypeId"
          class="legend-item"
        >
          <span class="legend-dot" :style="{ background: color }"></span>
          {{ subtypeNames[subtypeId] || `Type ${subtypeId}` }}
        </span>
      </template>
      <!-- Show asset type legend when no type is selected -->
      <template v-else>
        <span
          v-for="(color, assetType) in visibleAssetTypes"
          :key="assetType"
          class="legend-item"
        >
          <span class="legend-dot" :style="{ background: color }"></span>
          {{ assetTypeLabels[assetType] || assetType }}
        </span>
      </template>
    </div>

    <div class="picker-controls" v-if="pickerMode">
      <span class="picker-message">Click on the map to set location</span>
      <span v-if="pickedPosition" class="picker-coords">
        Position: {{ pickedPosition.left }}, {{ pickedPosition.top }}
      </span>
      <button class="btn btn-secondary btn-sm" @click="clearPosition">Clear</button>
    </div>

    <div ref="mapContainer" class="map-container" :class="{ 'picker-active': pickerMode }"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import { loadMapConfig, blueprintUrlFor, state as mapConfig } from '../composables/mapConfig'
import { assetTypeLabel, assetDetailRoute } from '../utils/assetTypes'

const props = defineProps({
  machines: { type: Array, default: () => [] },
  machinetypes: { type: Array, default: () => [] },
  businessunits: { type: Array, default: () => [] },
  statuses: { type: Array, default: () => [] },
  theme: { type: String, default: 'dark' },
  pickerMode: { type: Boolean, default: false },
  initialPosition: { type: Object, default: null },  // { left, top }
  assetTypeMode: { type: Boolean, default: false },  // When true, use unified asset format
  selectedAssetType: { type: String, default: '' },  // Currently selected asset type filter
  subtypeColors: { type: Object, default: () => ({}) },  // Map of subtype ID to color
  subtypeNames: { type: Object, default: () => ({}) }  // Map of subtype ID to name
})

const emit = defineEmits(['markerClick', 'positionPicked'])

const mapContainer = ref(null)
let map = null
let imageOverlay = null
const markers = ref([])
const pickedPosition = ref(null)
let pickerMarker = null
let markerLayer = null
let canvasRenderer = null

const filters = ref({
  machinetype: '',
  businessunit: '',
  status: '',
  search: ''
})

// Map dimensions - facility blueprint size, loaded from settings before
// initMap runs (mutable so the loaded values replace the fallback defaults).
let MAP_WIDTH = mapConfig.width
let MAP_HEIGHT = mapConfig.height

// Asset type colors (for unified map mode) - normalized lookup
const assetTypeColorsMap = {
  'equipment': '#F44336',       // Red
  'computer': '#2196F3',        // Blue
  'printer': '#4CAF50',         // Green
  'network device': '#FF9800',  // Orange
  'network_device': '#FF9800'   // Orange (alternate key)
}

// Get asset type color with case-insensitive lookup
function getAssetTypeColor(assettype) {
  if (!assettype) return '#BDBDBD'
  const normalized = assettype.toLowerCase()
  return assetTypeColorsMap[normalized] || '#BDBDBD'
}

// Asset-type display labels come from the shared util (single source of truth).
const assetTypeLabels = new Proxy({}, {
  get(target, prop) {
    return typeof prop === 'string' ? assetTypeLabel(prop) : prop
  }
})

// Type colors - distinct colors for each machine type
const typeColors = {
  // Machining
  'Mill': '#F44336',           // Red
  'Lathe': '#E91E63',          // Pink
  'Grinder': '#2196F3',        // Blue
  'Broach': '#00BCD4',         // Cyan
  'Hobbing': '#009688',        // Teal
  'Turn': '#FF5722',           // Deep Orange (Mill Turn, Vertical Turn)

  // Inspection & Measurement
  'CMM': '#9C27B0',            // Purple
  'Measuring': '#7B1FA2',      // Dark Purple
  'Eddy': '#673AB7',           // Deep Purple
  'Inspection': '#8BC34A',     // Light Green

  // Heat Treatment & Processing
  'Furnace': '#FF9800',        // Orange
  'Wash': '#4CAF50',           // Green
  'Wax': '#FFEB3B',            // Yellow

  // Automation
  'Robot': '#3F51B5',          // Indigo
  'Deburr': '#5C6BC0',         // Indigo Light

  // Welding
  'Welder': '#795548',         // Brown

  // IT/Network
  'PC': '#607D8B',             // Blue Grey
  'Printer': '#78909C',        // Blue Grey Light
  'Switch': '#546E7A',         // Blue Grey Dark
  'Access Point': '#455A64',   // Blue Grey Darker
  'IDF': '#37474F',            // Blue Grey Very Dark

  // Other
  'Saw': '#8D6E63',            // Brown Light
  'Press': '#A1887F',          // Brown Lighter
  'EDM': '#00ACC1',            // Cyan Dark
  'Drill': '#26A69A',          // Teal Light
  'CNC': '#66BB6A',            // Green Light
  'Assembly': '#CDDC39',       // Lime
  'Other': '#BDBDBD'           // Grey
}

function getTypeColor(typeName) {
  if (!typeName) return '#BDBDBD'
  for (const [key, color] of Object.entries(typeColors)) {
    if (typeName.toLowerCase().includes(key.toLowerCase())) {
      return color
    }
  }
  return '#BDBDBD'  // Grey for unknown types
}

// Get unique visible types from machines
const visibleTypes = computed(() => {
  const typeIds = new Set(props.machines.map(m => m.machinetypeid))
  return props.machinetypes.filter(t => typeIds.has(t.machinetypeid))
})

// Get unique visible asset types (for asset mode)
const visibleAssetTypes = computed(() => {
  const types = new Set(props.machines.map(m => m.assettype).filter(Boolean))
  const result = {}
  for (const t of types) {
    result[t] = getAssetTypeColor(t)
  }
  return result
})

// Get subtype ID from asset based on asset type
function getSubtypeId(asset) {
  if (!asset.typedata) return null
  // Normalize network_device -> network device so the subtype id resolves.
  const typeLower = (asset.assettype || '').toLowerCase().replace(/_/g, ' ')
  if (typeLower === 'equipment') return asset.typedata.equipmenttypeid
  if (typeLower === 'computer') return asset.typedata.computertypeid
  if (typeLower === 'network device') return asset.typedata.networkdevicetypeid
  if (typeLower === 'printer') return asset.typedata.printertypeid
  return null
}

// Get visible subtypes when a type is selected
const visibleSubtypes = computed(() => {
  if (!props.selectedAssetType) return {}
  const subtypeIds = new Set(
    props.machines
      .map(m => getSubtypeId(m))
      .filter(id => id != null)
  )
  const result = {}
  for (const id of subtypeIds) {
    if (props.subtypeColors[id]) {
      result[id] = props.subtypeColors[id]
    }
  }
  return result
})

function initMap() {
  if (!mapContainer.value) return

  // Use canvas renderer for performance - renders all markers on a single <canvas>
  canvasRenderer = L.canvas({ padding: 0.5 })

  map = L.map(mapContainer.value, {
    crs: L.CRS.Simple,
    minZoom: -4,
    maxZoom: 2,
    attributionControl: false,
    renderer: canvasRenderer
  })

  const bounds = [[0, 0], [MAP_HEIGHT, MAP_WIDTH]]
  imageOverlay = L.imageOverlay(blueprintUrlFor(props.theme), bounds)
  imageOverlay.addTo(map)

  // Set initial view - zoom out to show full floor plan
  const initialZoom = -2
  map.setView([MAP_HEIGHT / 2, MAP_WIDTH / 2], initialZoom)
  map.setMaxBounds(bounds)

  // Picker mode: click to set position
  if (props.pickerMode) {
    map.on('click', handleMapClick)

    // Show initial position if provided
    if (props.initialPosition) {
      setPickerPosition(props.initialPosition.left, props.initialPosition.top)
    }
  } else {
    renderMarkers()
  }
}

function handleMapClick(e) {
  if (!props.pickerMode) return

  const leafletY = e.latlng.lat
  const leafletX = e.latlng.lng

  // Convert back to database coordinates
  const dbLeft = Math.round(leafletX)
  const dbTop = Math.round(MAP_HEIGHT - leafletY)

  setPickerPosition(dbLeft, dbTop)
}

function setPickerPosition(left, top) {
  // Remove old picker marker
  if (pickerMarker) {
    pickerMarker.remove()
  }

  pickedPosition.value = { left, top }

  // Convert to Leaflet coordinates
  const leafletY = MAP_HEIGHT - top
  const leafletX = left

  const icon = L.divIcon({
    html: `<div class="picker-marker-dot"></div>`,
    iconSize: [16, 16],
    iconAnchor: [8, 8],
    className: 'picker-marker'
  })

  pickerMarker = L.marker([leafletY, leafletX], { icon, draggable: true })
  pickerMarker.addTo(map)

  // Allow dragging to fine-tune position
  pickerMarker.on('dragend', () => {
    const pos = pickerMarker.getLatLng()
    const newLeft = Math.round(pos.lng)
    const newTop = Math.round(MAP_HEIGHT - pos.lat)
    pickedPosition.value = { left: newLeft, top: newTop }
    emit('positionPicked', pickedPosition.value)
  })

  emit('positionPicked', pickedPosition.value)
}

function clearPosition() {
  if (pickerMarker) {
    pickerMarker.remove()
    pickerMarker = null
  }
  pickedPosition.value = null
  emit('positionPicked', null)
}

// Get the detail page route based on machine category
// Extensible for future addon types (network, cameras, etc.)
function getDetailRoute(machine) {
  const category = machine.category?.toLowerCase() || ''
  const routeMap = {
    'equipment': '/machines',
    'pc': '/pcs',
    'printer': '/printers',
    // Future addon routes can be added here:
    // 'network': '/network',
    // 'camera': '/cameras',
  }
  const basePath = routeMap[category] || '/machines'
  return `${basePath}/${machine.machineid}`
}

function renderMarkers() {
  // Clear existing markers
  markers.value.forEach(m => m.marker.remove())
  markers.value = []

  props.machines.forEach(item => {
    if (item.mapx == null || item.mapy == null) return

    // Transform coordinates (database Y is top-down, Leaflet is bottom-up)
    const leafletY = MAP_HEIGHT - item.mapy
    const leafletX = item.mapx

    // Determine color based on mode
    let color, typeName, displayName, detailRoute

    if (props.assetTypeMode) {
      // Unified asset mode - use subtype colors when a type is selected
      if (props.selectedAssetType) {
        const subtypeId = getSubtypeId(item)
        color = (subtypeId && props.subtypeColors[subtypeId]) || '#BDBDBD'
        typeName = (subtypeId && props.subtypeNames[subtypeId]) || item.assettype || ''
      } else {
        // Prefer the stored AssetType.color; fall back to the built-in map.
        color = item.assettypecolor || getAssetTypeColor(item.assettype)
        typeName = item.assettype || ''
      }
      displayName = item.displayname || item.name || item.assetnumber || 'Unknown'
      detailRoute = getAssetDetailRoute(item)
    } else {
      // Legacy machine mode
      typeName = item.machinetype || ''
      color = getTypeColor(typeName)
      displayName = item.alias || item.machinenumber || 'Unknown'
      detailRoute = getDetailRoute(item)
    }

    // Use circleMarker instead of divIcon marker - renders on canvas
    // for much better performance (no DOM element per marker)
    const marker = L.circleMarker([leafletY, leafletX], {
      radius: 6,
      fillColor: color,
      color: 'rgba(255,255,255,0.8)',
      weight: 2,
      fillOpacity: 1,
      renderer: canvasRenderer
    })

    // Build tooltip content
    let tooltipLines = [`<strong>${displayName}</strong>`]

    if (props.assetTypeMode) {
      tooltipLines.push(`<span style="color: #888;">${item.assettype || 'Unknown'}</span>`)

      if (item.primaryip) {
        tooltipLines.push(`<span style="color: #8cf;">IP: ${item.primaryip}</span>`)
      }
      if (item.typedata?.hostname) {
        tooltipLines.push(`<span style="color: #8cf;">${item.typedata.hostname}</span>`)
      }
    } else {
      const category = item.category?.toLowerCase() || ''

      if (typeName && typeName.toLowerCase() !== 'locationonly') {
        tooltipLines.push(`<span style="color: #888;">${typeName}</span>`)
      }

      if (item.vendor) {
        tooltipLines.push(`<span style="color: #aaa;">${item.vendor}${item.model ? ' ' + item.model : ''}</span>`)
      } else if (item.model) {
        tooltipLines.push(`<span style="color: #aaa;">${item.model}</span>`)
      }

      if (category === 'printer') {
        if (item.ipaddress) {
          tooltipLines.push(`<span style="color: #8cf;">IP: ${item.ipaddress}</span>`)
        }
        if (item.hostname) {
          tooltipLines.push(`<span style="color: #8cf;">${item.hostname}</span>`)
        }
      } else {
        if (item.connected_pc) {
          tooltipLines.push(`<span style="color: #fc8;">PC: ${item.connected_pc}</span>`)
        }
      }
    }

    if (item.businessunit) {
      tooltipLines.push(`<span style="color: #ccc;">${item.businessunit}</span>`)
    }

    const tooltipContent = tooltipLines.join('<br>')
    marker.bindTooltip(tooltipContent, {
      direction: 'top',
      offset: [0, -12],
      className: 'marker-tooltip'
    })

    // Click popup (detailed info)
    let popupContent
    if (props.assetTypeMode) {
      popupContent = `
        <div class="marker-popup">
          <strong>${displayName}</strong>
          <div class="popup-details">
            <div><span class="label">Asset #:</span> ${item.assetnumber || '-'}</div>
            <div><span class="label">Type:</span> ${item.assettype || '-'}</div>
            <div><span class="label">Status:</span> ${item.status || '-'}</div>
            <div><span class="label">Location:</span> ${item.location || '-'}</div>
            ${item.primaryip ? `<div><span class="label">IP:</span> ${item.primaryip}</div>` : ''}
          </div>
          <a href="${detailRoute}" class="popup-link">View Details</a>
        </div>
      `
    } else {
      popupContent = `
        <div class="marker-popup">
          <strong>${displayName}</strong>
          <div class="popup-details">
            <div><span class="label">Number:</span> ${item.machinenumber || '-'}</div>
            <div><span class="label">Type:</span> ${typeName || '-'}</div>
            <div><span class="label">Category:</span> ${item.category || '-'}</div>
            <div><span class="label">Status:</span> ${item.status || '-'}</div>
            <div><span class="label">Vendor:</span> ${item.vendor || '-'}</div>
            <div><span class="label">Model:</span> ${item.model || '-'}</div>
          </div>
          <a href="${detailRoute}" class="popup-link">View Details</a>
        </div>
      `
    }

    marker.bindPopup(popupContent)
    marker.on('click', () => emit('markerClick', item))

    marker.addTo(map)

    // Build search data
    const searchData = props.assetTypeMode
      ? `${item.assetnumber} ${item.name} ${item.displayname} ${item.assettype} ${item.status} ${item.businessunit} ${item.typedata?.hostname || ''} ${item.primaryip || ''}`.toLowerCase()
      : `${item.machinenumber} ${item.alias} ${typeName} ${item.vendor} ${item.model} ${item.serialnumber} ${item.businessunit}`.toLowerCase()

    markers.value.push({
      marker,
      machine: item,
      searchData
    })
  })

  applyFilters()
}

// Get detail route for unified asset format (shared util = single source).
function getAssetDetailRoute(asset) {
  return assetDetailRoute(asset)
}

function applyFilters() {
  const searchTerm = filters.value.search.toLowerCase()

  markers.value.forEach(({ marker, machine, searchData }) => {
    let visible = true

    if (filters.value.machinetype && machine.machinetypeid !== filters.value.machinetype) {
      visible = false
    }
    if (filters.value.businessunit && machine.businessunitid !== filters.value.businessunit) {
      visible = false
    }
    if (filters.value.status && machine.statusid !== filters.value.status) {
      visible = false
    }
    if (searchTerm && !searchData.includes(searchTerm)) {
      visible = false
    }

    marker.setStyle({ fillOpacity: visible ? 1 : 0.15, opacity: visible ? 1 : 0.15 })
  })
}

let searchTimeout = null
function debounceSearch() {
  clearTimeout(searchTimeout)
  searchTimeout = setTimeout(applyFilters, 300)
}

watch(() => props.machines, (newVal, oldVal) => {
  if (map && newVal !== oldVal) renderMarkers()
})

watch(() => props.theme, (newTheme) => {
  if (imageOverlay && map) {
    imageOverlay.setUrl(blueprintUrlFor(newTheme))
  }
})

onMounted(async () => {
  // Load this facility's blueprint + dimensions before building the map so
  // bounds and coordinate math use the right size. Falls back to defaults.
  await loadMapConfig()
  MAP_WIDTH = mapConfig.width
  MAP_HEIGHT = mapConfig.height
  initMap()
})

onUnmounted(() => {
  if (map) {
    map.remove()
    map = null
  }
})
</script>

<style scoped>
.shopfloor-map {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.map-controls {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem;
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
  gap: 0.5rem;
}

.filters {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.filters select,
.filters input {
  padding: 0.625rem 1rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 1rem;
  background: var(--bg);
  color: var(--text);
}

.filters select {
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23999' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.25rem;
  min-width: 160px;
}

.filters input {
  width: 280px;
}

.filters input::placeholder {
  color: var(--text-light);
  opacity: 0.7;
}

.filters input::placeholder {
  color: var(--text-light);
}

.legend {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  font-size: 1.125rem;
  color: var(--text);
}

.map-legend-bar {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  font-size: 1rem;
  color: var(--text);
  padding: 0.5rem 1rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-bottom: 0.5rem;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.legend-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid var(--bg-card);
  box-shadow: 0 1px 4px rgba(0,0,0,0.4);
}

.map-container {
  flex: 1;
  min-height: 600px;
  background: var(--bg);
  border: 1px solid var(--border);
}

.map-container.picker-active {
  cursor: crosshair;
}

.picker-controls {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1rem;
  background: var(--warning);
  border-bottom: 1px solid var(--warning);
  font-size: 1.125rem;
}

.picker-message {
  font-weight: 500;
  color: #1a1a1a;
}

.picker-coords {
  font-family: monospace;
  background: var(--bg-card);
  color: var(--text);
  padding: 0.375rem 0.75rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  font-size: 1.125rem;
}

:deep(.marker-popup) {
  min-width: 320px;
}

:deep(.marker-popup strong) {
  display: block;
  margin-bottom: 0.625rem;
  font-size: 1.5rem;
}

:deep(.popup-details) {
  font-size: 1.125rem;
  line-height: 1.9;
}

:deep(.popup-details .label) {
  color: #666;
  font-weight: 500;
}

:deep(.popup-link) {
  display: inline-block;
  margin-top: 1rem;
  color: #1976d2;
  text-decoration: none;
  font-size: 1.125rem;
  font-weight: 500;
}

:deep(.popup-link:hover) {
  text-decoration: underline;
}

:deep(.machine-marker) {
  background: transparent !important;
  border: none !important;
}

:deep(.machine-marker-dot) {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.8);
  box-shadow: 0 1px 4px rgba(0,0,0,0.5);
}

:deep(.picker-marker-dot) {
  background: #ff0000;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--border);
  box-shadow: 0 2px 6px rgba(0,0,0,0.5);
}

:deep(.marker-tooltip) {
  background: rgba(0, 0, 0, 0.92);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 14px 18px;
  font-size: 1.125rem;
  line-height: 1.7;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
  max-width: 400px;
}

:deep(.marker-tooltip::before) {
  border-top-color: rgba(0, 0, 0, 0.92);
}

/* Legend bar for asset type mode (no filters - parent handles them) */
.map-legend {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding: 0.75rem 1rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 0.75rem;
  font-size: 0.875rem;
  color: var(--text);
}
</style>
