package de.jadehs.strassenschadenpro2.pages

import android.Manifest
import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.arcgismaps.location.LocationDisplayAutoPanMode
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Viewpoint
import com.arcgismaps.toolkit.geoviewcompose.MapView
import com.arcgismaps.toolkit.geoviewcompose.rememberLocationDisplay
import de.jadehs.strassenschadenpro2.BuildConfig
import de.jadehs.strassenschadenpro2.FeatureOperationType
import de.jadehs.strassenschadenpro2.MapViewModel
import de.jadehs.strassenschadenpro2.components.DropDownMenuBox
import kotlinx.coroutines.launch

@Composable
fun MapPage(modifier: Modifier = Modifier,
            mapViewModel: MapViewModel,
            selectedObjectId: Int? = null,
            onObjectIdUsed: () -> Unit = {}) {
    val context = LocalContext.current
    val coroutineScope = rememberCoroutineScope()

    var featureManagementDropdownIndex by remember { mutableIntStateOf(0) }

    ArcGISEnvironment.applicationContext = context.applicationContext
    ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ARCGIS_TOKEN)

    val snackbarHostState = remember { SnackbarHostState() }

    val locationDisplay = rememberLocationDisplay().apply {
        setAutoPanMode(LocationDisplayAutoPanMode.Off)
    }

    LaunchedEffect(selectedObjectId) {
        selectedObjectId?.let{
            mapViewModel.zoomToFeature(selectedObjectId)
            onObjectIdUsed()
        }
    }

    if (checkPermissions(context)) {
        // Permissions are already granted.
        LaunchedEffect(Unit) {
            locationDisplay.dataSource.start()
        }
    } else {
        RequestPermissions(
            context = context,
            onPermissionsGranted = {
                coroutineScope.launch {
                    locationDisplay.dataSource.start()
                }
            }
        )
    }



    Column(
        modifier = modifier
            .fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        MapView(
            modifier = Modifier.weight(90f),
            arcGISMap = mapViewModel.map,
            locationDisplay = locationDisplay,
            mapViewProxy = mapViewModel.mapViewProxy,
            onSingleTapConfirmed = mapViewModel::onTap,
        ) {
            mapViewModel.selectedFeature?.let { selectedFeature ->
                // Only show the delete button when on the delete feature operation and a feature is selected.
                if (mapViewModel.currentFeatureOperation == FeatureOperationType.DELETE) {
                    Callout(geoElement = selectedFeature) {
                        Button(onClick = mapViewModel::deleteSelectedFeature) {
                            Text(text = "Delete")
                        }
                    }
                }
                // Only show the dropdown for damage type when on the update feature operation.
                if (mapViewModel.currentFeatureOperation == FeatureOperationType.UPDATE_ATTRIBUTE) {
                    Callout(geoElement = selectedFeature) {
                        DropDownMenuBox(
                            modifier = Modifier
                                .padding(8.dp),
                            textFieldLabel = "Select damage type",
                            textFieldValue = mapViewModel.currentDamageType,
                            dropDownItemList = mapViewModel.damageTypeList,
                            onIndexSelected = { index ->
                                if (mapViewModel.selectedFeature != null) {
                                    mapViewModel.onDamageTypeSelected(index)
                                } else {
                                    coroutineScope.launch {
                                        snackbarHostState.showSnackbar("Please select a feature to update")
                                    }
                                }
                            }
                        )
                    }
                }
            }
        }
        DropDownMenuBox(
            modifier = Modifier.weight(10f).padding(end = 8.dp),
            textFieldLabel = "Feature management operation",
            textFieldValue = mapViewModel.currentFeatureOperation.operationName,
            dropDownItemList = FeatureOperationType.entries.map { entry -> entry.operationName },
            onIndexSelected = { index ->
                mapViewModel.onFeatureOperationSelected(index)
                featureManagementDropdownIndex = index
            })
    }
}

fun checkPermissions(context: Context): Boolean {
    // Check permissions to see if both permissions are granted.
    // Coarse location permission.
    val permissionCheckCoarseLocation = ContextCompat.checkSelfPermission(
        context,
        Manifest.permission.ACCESS_COARSE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED
    // Fine location permission.
    val permissionCheckFineLocation = ContextCompat.checkSelfPermission(
        context,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED

    return permissionCheckCoarseLocation && permissionCheckFineLocation
}

fun showError(context: Context, message: String) {
    Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}

@Composable
fun RequestPermissions(context: Context, onPermissionsGranted: () -> Unit) {

    // Create an activity result launcher using permissions contract and handle the result.
    val activityResultLauncher = rememberLauncherForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        // Check if both fine & coarse location permissions are true.
        if (permissions.all { it.value }) {
            onPermissionsGranted()
        } else {
            showError(context, "Location permissions were denied")
        }
    }

    LaunchedEffect(Unit) {
        activityResultLauncher.launch(
            // Request both fine and coarse location permissions.
            arrayOf(
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION
            )
        )
    }


}