package center.sciprog.maps.compose

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpSize
import center.sciprog.maps.coordinates.*
import kotlin.math.PI
import kotlin.math.log2
import kotlin.math.min


//TODO consider replacing by modifier
/**
 * @param onDrag - returns true if you want to drag a map and false, if you want to make map stationary.
 *          start - is a point where drag begins, end is a point where drag ends
 */
public data class MapViewConfig(
    val zoomSpeed: Double = 1.0 / 3.0,
    val inferViewBoxFromFeatures: Boolean = false,
    val onClick: MapViewPoint.() -> Unit = {},
    val onDrag: (start: MapViewPoint, end: MapViewPoint) -> Boolean = { _, _ -> true },
    val onViewChange: MapViewPoint.() -> Unit = {},
    val onSelect: (GmcRectangle) -> Unit = {},
    val zoomOnSelect: Boolean = true,
    val resetViewPoint: Boolean = false,
)

@Composable
public expect fun MapView(
    mapTileProvider: MapTileProvider,
    computeViewPoint: (canvasSize: DpSize) -> MapViewPoint,
    features: Map<FeatureId, MapFeature>,
    config: MapViewConfig = MapViewConfig(),
    modifier: Modifier = Modifier.fillMaxSize(),
)

@Composable
public fun MapView(
    mapTileProvider: MapTileProvider,
    initialViewPoint: MapViewPoint,
    features: Map<FeatureId, MapFeature> = emptyMap(),
    config: MapViewConfig = MapViewConfig(),
    modifier: Modifier = Modifier.fillMaxSize(),
    buildFeatures: @Composable (MapFeatureBuilder.() -> Unit) = {},
) {
    val featuresBuilder = MapFeatureBuilderImpl(features)
    featuresBuilder.buildFeatures()
    MapView(
        mapTileProvider,
        { initialViewPoint },
        featuresBuilder.build(),
        config,
        modifier
    )
}

internal fun GmcRectangle.computeViewPoint(mapTileProvider: MapTileProvider): (canvasSize: DpSize) -> MapViewPoint =
    { canvasSize ->
        val zoom = log2(
            min(
                canvasSize.width.value / longitudeDelta.radians.value,
                canvasSize.height.value / latitudeDelta.radians.value
            ) * PI / mapTileProvider.tileSize
        )
        MapViewPoint(center, zoom)
    }

@Composable
public fun MapView(
    mapTileProvider: MapTileProvider,
    box: GmcRectangle,
    features: Map<FeatureId, MapFeature> = emptyMap(),
    config: MapViewConfig = MapViewConfig(),
    modifier: Modifier = Modifier.fillMaxSize(),
    buildFeatures: @Composable (MapFeatureBuilder.() -> Unit) = {},
) {
    val featuresBuilder = MapFeatureBuilderImpl(features)
    featuresBuilder.buildFeatures()
    MapView(
        mapTileProvider,
        box.computeViewPoint(mapTileProvider),
        featuresBuilder.build(),
        config,
        modifier
    )
}