DefaultMovieCreditsRepository.kt

package com.louisfn.somovie.data.repository

import androidx.annotation.AnyThread
import com.louisfn.somovie.core.common.annotation.DefaultDispatcher
import com.louisfn.somovie.data.database.datasource.MovieCreditsLocalDataSource
import com.louisfn.somovie.data.mapper.MovieCreditsMapper
import com.louisfn.somovie.data.network.datasource.MovieCreditsRemoteDataSource
import com.louisfn.somovie.domain.model.MovieCredits
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.invoke
import javax.inject.Inject

interface MovieCreditsRepository {

    @AnyThread
    fun movieCreditsChanges(movieId: Long): Flow<MovieCredits>

    @AnyThread
    suspend fun refreshMovieCredits(movieId: Long)
}

internal class DefaultMovieCreditsRepository @Inject constructor(
    private val remoteDataSource: MovieCreditsRemoteDataSource,
    private val localDataSource: MovieCreditsLocalDataSource,
    private val mapper: MovieCreditsMapper,
    @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher,
) : MovieCreditsRepository {

    override fun movieCreditsChanges(movieId: Long): Flow<MovieCredits> =
        movieCreditsChangesFromLocal(movieId)

    override suspend fun refreshMovieCredits(movieId: Long) {
        defaultDispatcher {
            remoteDataSource.getMovieCredits(movieId)
                .also {
                    with(localDataSource) {
                        replaceActors(movieId, mapper.mapCastToEntity(it))
                        replaceCrewMembers(movieId, mapper.mapCrewToEntity(it))
                    }
                }
        }
    }

    @AnyThread
    private fun movieCreditsChangesFromLocal(movieId: Long): Flow<MovieCredits> =
        combine(
            localDataSource.actorsChanges(movieId),
            localDataSource.crewMembersChanges(movieId),
        ) { actors, crewMembers -> mapper.mapToDomain(actors, crewMembers) }
            .flowOn(defaultDispatcher)
}