package dev.adriankuta.flights.ui.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.adriankuta.flights.core.util.Result
import dev.adriankuta.flights.core.util.asResult
import dev.adriankuta.flights.domain.stations.ObserveAirportsGroupedByCountry
import dev.adriankuta.flights.domain.types.AirportInfo
import dev.adriankuta.flights.domain.types.Country
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject

@HiltViewModel
internal class StationsScreenViewModel @Inject constructor(
    observeAirportsGroupedByCountry: ObserveAirportsGroupedByCountry,
) : ViewModel() {

    private val _searchQuery = MutableStateFlow("")
    val searchQuery: StateFlow<String> = _searchQuery

    private val _selectedOriginAirport = MutableStateFlow<AirportInfo?>(null)
    val selectedOriginAirport: StateFlow<AirportInfo?> = _selectedOriginAirport

    fun onSearchQueryChanged(query: String) {
        _searchQuery.value = query
    }

    fun onAirportSelected(airport: AirportInfo) {
        _selectedOriginAirport.value = airport
    }

    fun clearSelectedAirport() {
        _selectedOriginAirport.value = null
    }

    val originAirports = originAirportsUiState(
        useCase = observeAirportsGroupedByCountry,
        searchQuery = searchQuery,
    ).stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = OriginAirportsUiState.Loading,
    )
}

private fun originAirportsUiState(
    useCase: ObserveAirportsGroupedByCountry,
    searchQuery: StateFlow<String>,
): Flow<OriginAirportsUiState> {
    return combine(
        useCase().asResult(),
        searchQuery,
    ) { result, query ->
        when (result) {
            is Result.Error -> OriginAirportsUiState.Error(result.exception)
            is Result.Loading -> OriginAirportsUiState.Loading
            is Result.Success -> {
                val airports = result.data.orEmpty()
                if (query.isBlank()) {
                    OriginAirportsUiState.Success(airports)
                } else {
                    val filteredAirports = airports.mapValues { (_, airportList) ->
                        airportList.filter { airport ->
                            airport.name.contains(query, ignoreCase = true) ||
                                airport.code.contains(query, ignoreCase = true) ||
                                airport.city.name.contains(query, ignoreCase = true) ||
                                airport.country.name.contains(query, ignoreCase = true)
                        }
                    }.filterValues { it.isNotEmpty() }
                    OriginAirportsUiState.Success(filteredAirports)
                }
            }
        }
    }
}

internal sealed interface OriginAirportsUiState {
    data object Loading : OriginAirportsUiState
    data class Success(val groupedAirports: Map<Country, List<AirportInfo>>) : OriginAirportsUiState
    data class Error(val exception: Throwable) : OriginAirportsUiState
}

internal sealed interface DestinationAirportsUiState {
    data object Loading : DestinationAirportsUiState
    data class Success(val airports: List<AirportInfo>) : DestinationAirportsUiState
    data class Error(val exception: Throwable) : DestinationAirportsUiState
}
