package com.isidroid.c23.domain.use_case

import android.Manifest
import android.content.Context
import androidx.compose.ui.text.intl.Locale
import com.isidroid.c23.JobNotFoundException
import com.isidroid.c23.NoLocationPermissionException
import com.isidroid.c23.constant.Argument
import com.isidroid.c23.data.mapper.createListItem
import com.isidroid.c23.domain.dto.PrintJobListItem
import com.isidroid.c23.ext.getPrintJobStatus
import com.isidroid.c23.ext.getPrintJobStatusColor
import com.isidroid.c23.ext.hasNotificationPermission
import com.isidroid.c23.ext.isDebug
import com.isidroid.core.FlowResult
import com.isidroid.job.repository.JobRepository
import com.isidroid.job_sender.domain.dto.JobSenderResult
import com.isidroid.location.ext.isMileUnit
import com.isidroid.location.repository.LocationRepository
import com.isidroid.spot.repository.SpotRepository
import com.isidroid.ui.maps.ext.addKilometerToLatLng
import com.isidroid.ui.maps.model.MapMarker
import com.isidroid.utils.hasPermission
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.flow
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.round

@Singleton
class DetailsUseCase @Inject constructor(
    @ApplicationContext private val context: Context,
    private val jobRepository: JobRepository,
    private val spotRepository: SpotRepository,
    private val locationRepository: LocationRepository,
) {
    fun loadDetails(id: String) = flow {
        emit(FlowResult.Loading)

        val hasLocationPermission = context.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)
        if (!hasLocationPermission) {
            throw NoLocationPermissionException()
        }

        val hasNotificationPermission = context.hasNotificationPermission


        val job = jobRepository.readLocalList(ids = listOf(id)).firstOrNull() ?: throw JobNotFoundException()
        val richSpot = spotRepository.findLocalRichSpots(ids = listOf(job.spotId))?.firstOrNull()

        val result = job.createListItem(context = context, richSpot = richSpot)
        val currentLocation = locationRepository.getCurrentLocation()
        val distanceKm = locationRepository.findDistance(
            currentLocation.first,
            currentLocation.second,
            richSpot?.spot?.lat,
            richSpot?.spot?.lng
        )?.let { (round(it * 100) / 100) }

        val distance = buildString {
            distanceKm?.let { append("$distanceKm ") }
            if (Locale.current.isMileUnit)
                append("miles")
            else
                append("km")
        }

        val location = if (isDebug() && richSpot?.spot != null)
            addKilometerToLatLng(richSpot.spot.lat, richSpot.spot.lng, distance = 0.2)
        else
            currentLocation

        val mapMarker = richSpot?.spot?.let { spot ->
            MapMarker(id = spot.id, lat = spot.lat, lng = spot.lng, name = spot.name)
        }

        emit(
            FlowResult.Success(
                mapOf(
                    Argument.INFO to result,
                    Argument.LATITUDE to location.first,
                    Argument.LONGITUDE to location.second,
                    Argument.MARKER to mapMarker,
                    Argument.DISTANCE to distance,
                    Argument.HAS_NOTIFICATION_PERMISSION to hasNotificationPermission
                )
            )
        )
    }

    fun updateStatuses(printJob: PrintJobListItem?, info: JobSenderResult.Statuses): PrintJobListItem? {
        return printJob?.copy(
            statusName = context.getString(getPrintJobStatus(info.status)),
            statusColor = getPrintJobStatusColor(info.status)
        )
    }
}