package com.prodhack.moscow2025.data.repImplementations

import com.prodhack.moscow2025.data.base.BaseRepository
import com.prodhack.moscow2025.data.data_providers.api.ApiKtorClient
import com.prodhack.moscow2025.data.data_providers.local_db.AppDatabase
import com.prodhack.moscow2025.data.data_providers.local_db.entities.mapToDB
import com.prodhack.moscow2025.data.dto.UserResponse
import com.prodhack.moscow2025.data.dto.mapToData
import com.prodhack.moscow2025.domain.interfaces.UserRepository
import com.prodhack.moscow2025.domain.models.UpdateUserData
import com.prodhack.moscow2025.domain.models.User
import io.ktor.client.request.setBody
import io.ktor.client.request.url
import io.ktor.http.ContentType
import io.ktor.http.HttpMethod
import io.ktor.http.contentType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.annotation.Single

@Single
class UserRepositoryImpl(
	ktorClient: ApiKtorClient,
	override val db: AppDatabase
) : UserRepository, BaseRepository() {

	override val defaultKtorClient = ktorClient.client
	private val userDao = db.userDao()

	override fun observeUser(): Flow<User?> {
		CoroutineScope(Dispatchers.IO).launch {
			fetchProfile()
		}
		return userDao.observeUser().map {
			it?.mapToDomain()
		}
	}

	private suspend fun writeProfileToDB(data: User) {
		userDao.upsert(data.mapToDB())
	}

	override suspend fun fetchProfile(): Result<User> = networkRequest<UserResponse> {
		url {
			method = HttpMethod.Get
			url("/profile")
		}
	}.map {
		it.mapToDomain().also {
			writeProfileToDB(it)
		}
	}

	override suspend fun updateProfile(request: UpdateUserData): Result<User> {
		return networkRequest<UserResponse> {
			url {
				method = HttpMethod.Patch
				url("/profile")
				setBody(request.mapToData())
				contentType(ContentType.Application.Json)
			}
		}.map {
			it.mapToDomain().also {
				writeProfileToDB(it)
			}
		}
	}

	override suspend fun clearLocalUserData() {
		userDao.clear()
	}
}