import SwiftUI
import MapKit

@available(iOS 17.0, *)
func convertToMapCamera(position: CameraPosition) -> MapCameraPosition {
  let coordinate = CLLocationCoordinate2D(
    latitude: position.coordinates.latitude,
    longitude: position.coordinates.longitude
  )
  return convertToMapCameraPosition(coordinate: coordinate, zoom: position.zoom)
}

@available(iOS 17.0, *)
func convertToMapCameraPosition(coordinate: CLLocationCoordinate2D, zoom: Double) -> MapCameraPosition {
  let longitudeDelta = 360 / pow(2, zoom)
  let latitudeDelta = longitudeDelta / cos(0 * .pi / 180)

  return MapCameraPosition.region(
    MKCoordinateRegion(
      center: coordinate,
      span: MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
    )
  )
}

@available(iOS 17.0, *)
func getLookAroundScene(from coordinate: CLLocationCoordinate2D) async throws -> MKLookAroundScene? {
  do {
    return try await MKLookAroundSceneRequest(coordinate: coordinate).scene
  } catch {
    throw SceneUnavailableAtLocationException()
  }
}

@available(iOS 17.0, *)
extension View {
  func renderCircle(_ circle: Circle) -> some MapContent {
    let mapCircle = MapCircle(center: circle.clLocationCoordinate2D, radius: circle.radius)
    return mapCircle
      .stroke(circle.lineColor ?? .clear, lineWidth: circle.lineWidth ?? 0)
      .foregroundStyle(circle.color)
  }

  func renderPolygon(_ polygon: Polygon) -> some MapContent {
    let mapPolygon = MapPolygon(coordinates: polygon.clLocationCoordinates2D)
    return mapPolygon
      .stroke(polygon.lineColor ?? .clear, lineWidth: polygon.lineWidth ?? 0)
      .foregroundStyle(polygon.color)
  }
}

// nearest marker to a tap point within a screen-space threshold (marker hit-test)
@available(iOS 17.0, *)
func nearestMarker(
  to point: CGPoint,
  in markers: [MapMarker],
  using reader: MapProxy,
  threshold: CGFloat = 44
) -> MapMarker? {
  var best: (marker: MapMarker, distance: CGFloat)?
  for marker in markers {
    guard let markerPoint = reader.convert(marker.clLocationCoordinate2D, to: .local) else {
      continue
    }
    let distance = hypot(markerPoint.x - point.x, markerPoint.y - point.y)
    guard distance <= threshold else { continue }
    if best == nil || distance < best!.distance {
      best = (marker, distance)
    }
  }
  return best?.marker
}

func markerClickPayload(_ marker: MapMarker) -> [String: Any] {
  [
    "id": marker.id,
    "title": marker.title,
    "tintColor": marker.tintColor,
    "systemImage": marker.systemImage,
    "monogram": marker.monogram,
    "coordinates": [
      "latitude": marker.coordinates.latitude,
      "longitude": marker.coordinates.longitude
    ]
  ]
}
