package com.omixlab.lckcontrol.data.repository

import com.omixlab.lckcontrol.data.local.dao.LinkedAccountDao
import com.omixlab.lckcontrol.data.local.entity.LinkedAccountEntity
import com.omixlab.lckcontrol.data.remote.CreateCustomRtmpRequest
import com.omixlab.lckcontrol.data.remote.LckApiService
import com.omixlab.lckcontrol.data.remote.ProviderCallbackRequest
import com.omixlab.lckcontrol.shared.LinkedAccount
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class AccountRepository @Inject constructor(
    private val accountDao: LinkedAccountDao,
    private val apiService: LckApiService,
) {
    fun observeAccounts(): Flow<List<LinkedAccount>> =
        accountDao.observeAll().map { entities ->
            entities.map { it.toLinkedAccount() }
        }

    suspend fun getAccounts(): List<LinkedAccount> =
        accountDao.getAll().map { it.toLinkedAccount() }

    /** Fetch accounts from backend and sync to Room cache */
    suspend fun syncAccounts() {
        val remote = apiService.getLinkedAccounts()
        // Read local entities to preserve isEnabled across sync
        val localMap = accountDao.getAll().associateBy { it.id }
        val entities = remote.map { account ->
            LinkedAccountEntity(
                id = account.id,
                serviceId = account.serviceId,
                displayName = account.displayName,
                accountId = account.accountId,
                avatarUrl = account.avatarUrl,
                isEnabled = localMap[account.id]?.isEnabled ?: true,
                rtmpUrl = account.rtmpUrl,
                streamKey = account.streamKey,
            )
        }
        // Detect removals
        val remoteIds = entities.map { it.id }.toSet()
        for (localAccount in localMap.values) {
            if (localAccount.id !in remoteIds) {
                accountDao.deleteById(localAccount.id)
            }
        }
        for (entity in entities) {
            accountDao.upsert(entity)
        }
    }

    suspend fun setAccountEnabled(id: String, enabled: Boolean) {
        accountDao.setEnabled(id, enabled)
    }

    /** Create a custom RTMP account on backend and sync */
    suspend fun createCustomRtmpAccount(displayName: String, rtmpUrl: String, streamKey: String) {
        apiService.createCustomRtmpAccount(CreateCustomRtmpRequest(displayName, rtmpUrl, streamKey))
        syncAccounts()
    }

    /** Get YouTube OAuth URL from backend (for Custom Tabs) */
    suspend fun getYouTubeAuthUrl(): String {
        val response = apiService.getYouTubeAuthUrl()
        return response.url
    }

    /** Get Twitch OAuth URL from backend (for Custom Tabs) */
    suspend fun getTwitchAuthUrl(): String {
        val response = apiService.getTwitchAuthUrl()
        return response.url
    }

    /** Send YouTube callback code to backend */
    suspend fun handleYouTubeCallback(code: String, state: String) {
        apiService.youtubeCallback(ProviderCallbackRequest(code, state))
        syncAccounts()
    }

    /** Send Twitch callback code to backend */
    suspend fun handleTwitchCallback(code: String, state: String) {
        apiService.twitchCallback(ProviderCallbackRequest(code, state))
        syncAccounts()
    }

    /** Unlink account via backend and update local cache */
    suspend fun unlinkAccount(accountId: String) {
        apiService.unlinkAccount(accountId)
        accountDao.deleteById(accountId)
    }

    private fun LinkedAccountEntity.toLinkedAccount() = LinkedAccount(
        id = id,
        serviceId = serviceId,
        displayName = displayName,
        accountId = accountId,
        avatarUrl = avatarUrl,
        isAuthenticated = true, // Backend manages auth state
        isEnabled = isEnabled,
        rtmpUrl = rtmpUrl,
        streamKey = streamKey,
    )
}
