package pl.firmatpp.kierowca.data

import android.content.Context
import android.net.Uri
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.toRequestBody
import pl.firmatpp.kierowca.data.api.ApiFactory
import pl.firmatpp.kierowca.data.api.MobileDriverApi
import pl.firmatpp.kierowca.data.model.BootstrapResponse
import pl.firmatpp.kierowca.data.model.DriverDto
import pl.firmatpp.kierowca.data.model.OtpResponse
import pl.firmatpp.kierowca.data.model.PhotoUploadResponse
import pl.firmatpp.kierowca.data.model.RequestOtpBody
import pl.firmatpp.kierowca.data.model.RouteResponse
import pl.firmatpp.kierowca.data.model.VerifyOtpBody

class DriverRepository(
    private val context: Context,
    private val api: MobileDriverApi = ApiFactory.mobileDriverApi(),
    private val tokenStore: TokenStore = TokenStore(context),
) {
    suspend fun requestOtp(phoneNumber: String): OtpResponse =
        api.requestOtp(RequestOtpBody(phoneNumber))

    suspend fun verifyOtp(phoneNumber: String, code: String, deviceName: String): DriverDto {
        val response = api.verifyOtp(VerifyOtpBody(phoneNumber, code, deviceName))
        val token = response.accessToken ?: error("Brak tokenu sesji.")
        tokenStore.save(token)
        return response.driver ?: error("Brak danych kierowcy.")
    }

    suspend fun bootstrap(date: String? = null): BootstrapResponse =
        api.bootstrap(authHeader(requireToken()), date)

    suspend fun route(routeId: String): RouteResponse =
        api.route(authHeader(requireToken()), routeId)

    suspend fun uploadPhoto(
        routeId: String,
        uri: Uri,
        source: String,
        metadata: PhotoUploadMetadata = PhotoUploadMetadata(),
    ): PhotoUploadResponse {
        val resolver = context.contentResolver
        val mimeType = resolver.getType(uri) ?: "image/jpeg"
        val bytes = resolver.openInputStream(uri)?.use { it.readBytes() } ?: error("Nie mozna odczytac zdjecia.")
        val body = bytes.toRequestBody(mimeType.toMediaTypeOrNull())
        val photo = MultipartBody.Part.createFormData("photo", "ladunek.jpg", body)
        val sourceBody = source.toRequestBody("text/plain".toMediaTypeOrNull())
        val metadataParts = metadata.toMultipartTextParts()

        return api.uploadPhoto(
            authHeader(requireToken()),
            routeId,
            photo,
            sourceBody,
            metadataParts["takenAt"],
            metadataParts["latitude"],
            metadataParts["longitude"],
            metadataParts["locationAccuracyMeters"],
        )
    }

    suspend fun logout() {
        val token = tokenStore.read()
        if (token != null) {
            runCatching { api.logout(authHeader(token)) }
        }
        tokenStore.clear()
    }

    suspend fun hasToken(): Boolean = tokenStore.read() != null

    suspend fun imageAuthHeader(): String? = tokenStore.read()?.let(::authHeader)

    private suspend fun requireToken(): String = tokenStore.read() ?: error("Brak aktywnej sesji.")

    private fun authHeader(token: String): String = "Bearer $token"
}
