package com.example.myapplication.api.bike

import android.util.Log
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.myapplication.api.MyServerService
import com.example.myapplication.database.AppContainer
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.database.entities.model.Bike
import com.example.myapplication.database.entities.model.BikeWithItems
import com.example.myapplication.database.entities.model.ItemFromBike
import com.example.myapplication.database.entities.repository.BikeRepository
import com.example.myapplication.database.entities.repository.OfflineBikeRepository
import com.example.myapplication.database.entities.repository.OfflineItemRepository
import com.example.myapplication.database.remotekeys.repository.OfflineRemoteKeyRepository
import kotlinx.coroutines.flow.Flow

class RestBikeRepository(
    private val service: MyServerService,
    private val dbBikeRepository: OfflineBikeRepository,
    private val dbItemRepository: OfflineItemRepository,
    private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
    private val database: AppDatabase
) : BikeRepository {
    override fun getAllBikes(): Flow<PagingData<Bike>> {
        Log.d(RestBikeRepository::class.simpleName, "Get bikes")

        val pagingSourceFactory = { dbBikeRepository.getAllBikesPagingSource() }

        @OptIn(ExperimentalPagingApi::class)
        return Pager(
            config = PagingConfig(
                pageSize = AppContainer.LIMIT,
                enablePlaceholders = false
            ),
            remoteMediator = BikeRemoteMediator(
                service,
                dbBikeRepository,
                dbItemRepository,
                dbRemoteKeyRepository,
                database,
            ),
            pagingSourceFactory = pagingSourceFactory
        ).flow
    }

    override suspend fun getBike(uid: Int): BikeWithItems {
        val bike = service.getBike(uid).toBike()

        val items = service.getItemsForBike(uid).map { x ->
            ItemFromBike(
                x.id,
                x.dateTime,
                x.weight,
                x.maxCount - service.getRents().flatMap { rent ->
                    rent.items.filter { item -> item.id == x.id }
                }.sumOf { item -> item.count },
                uid
            )
        }
        return BikeWithItems(bike, items)
    }

    override suspend fun insertBike(bike: Bike) {
        service.createBike(bike.toBikeRemote()).toBike()
    }

    override suspend fun updateBike(bike: Bike) {
        service.updateBike(bike.uid, bike.toBikeRemote()).toBike()
    }

    override suspend fun deleteBike(bike: Bike) {
        val cart = service.getUsers()
        cart.forEach { userRemote ->
            userRemote.items = userRemote.items.filter { x -> x.bikeId != bike.uid }
            userRemote.id?.let { service.updateUserCart(it, userRemote) }
        }
        val rents = service.getRents()
        rents.forEach { rentRemote ->
            rentRemote.items = rentRemote.items.filter { x -> x.bikeId != bike.uid }
            service.updateRent(rentRemote.id, rentRemote)
        }
        service.deleteBike(bike.uid)
        dbBikeRepository.deleteBike(bike)
    }
}