import type { PoiCategory, PoiSummary } from '@/domain/poi'

export interface PoiMapMarker {
  id: number
  latitude: number
  longitude: number
  iconPath: string
  width: number
  height: number
  anchor: {
    x: number
    y: number
  }
  callout: {
    content: string
    color: string
    fontSize: number
    borderRadius: number
    bgColor: string
    padding: number
    display: 'ALWAYS' | 'BYCLICK'
    textAlign: 'center'
  }
  zIndex: number
}

function stableHash(input: string): number {
  let hash = 2166136261
  for (let index = 0; index < input.length; index += 1) {
    hash ^= input.charCodeAt(index)
    hash = Math.imul(hash, 16777619)
  }

  return hash >>> 0
}

/** Builds collision-free numeric marker IDs without coupling IDs to filter order. */
export function buildMarkerIdMap(poiIds: readonly string[]): Map<number, string> {
  const result = new Map<number, string>()
  const sortedIds = Array.from(new Set(poiIds)).sort()

  sortedIds.forEach((poiId) => {
    let markerId = stableHash(poiId) & 0x7FFFFFFF
    if (markerId === 0)
      markerId = 1

    while (result.has(markerId))
      markerId = markerId === 0x7FFFFFFF ? 1 : markerId + 1

    result.set(markerId, poiId)
  })

  return result
}

function rpxToPx(rpx: number): number {
  return typeof uni !== 'undefined' && typeof uni.upx2px === 'function'
    ? uni.upx2px(rpx)
    : Math.round(rpx / 2)
}

function toMarkerDimensions(selected: boolean): { width: number, height: number } {
  const size = selected
    ? { width: 80, height: 94 }
    : { width: 64, height: 78 }

  return {
    width: rpxToPx(size.width),
    height: rpxToPx(size.height),
  }
}

export function createPoiMarkers(
  pois: readonly PoiSummary[],
  categories: readonly PoiCategory[],
  markerIdMap: ReadonlyMap<number, string>,
  selectedPoiId: string | null,
): PoiMapMarker[] {
  const categoryMap = new Map(categories.map(category => [category.code, category]))
  const idByPoi = new Map(Array.from(markerIdMap.entries()).map(([markerId, poiId]) => [poiId, markerId]))

  return pois.flatMap((poi) => {
    const category = categoryMap.get(poi.categoryCode)
    const markerId = idByPoi.get(poi.id)
    if (!category || markerId === undefined)
      return []

    const selected = poi.id === selectedPoiId
    const size = toMarkerDimensions(selected)
    return [{
      id: markerId,
      latitude: poi.latitude,
      longitude: poi.longitude,
      iconPath: selected ? category.selectedMarkerIcon : category.markerIcon,
      width: size.width,
      height: size.height,
      anchor: { x: 0.5, y: 1 },
      callout: {
        content: selected ? `${category.name} · ${poi.name}` : category.name,
        color: selected ? '#FFFFFF' : '#18201D',
        fontSize: 12,
        borderRadius: 8,
        bgColor: selected ? '#0E6247' : '#FFFFFF',
        padding: 6,
        display: selected ? 'ALWAYS' : 'BYCLICK',
        textAlign: 'center',
      },
      zIndex: selected ? 10 : 1,
    }]
  })
}
