// Copyright (C) 2026 Jason M. Schwefel. All Rights Reserved.
package com.coldboreballisticsllc.scopedope.data.ammo

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import com.coldboreballisticsllc.scopedope.data.ammo.builtin.BuiltinAmmoDatabase
import com.coldboreballisticsllc.scopedope.data.ammo.user.UserAmmoDatabase
import com.coldboreballisticsllc.scopedope.di.BuiltinDb
import com.coldboreballisticsllc.scopedope.di.UserDb
import com.coldboreballisticsllc.scopedope.domain.model.AmmoLoad
import com.coldboreballisticsllc.scopedope.ballistics.BcModel
import com.coldboreballisticsllc.scopedope.domain.repository.AmmoRepository
import com.coldboreballisticsllc.scopedope.domain.repository.DuplicateAmmoException
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class AmmoRepositoryImpl @Inject constructor(
    @BuiltinDb private val builtinDb: BuiltinAmmoDatabase,
    @UserDb    private val userDb:    UserAmmoDatabase,
) : AmmoRepository {

    override fun observeAll(): Flow<List<AmmoLoad>> =
        builtinDb.ammoDao().observeAll()
            .catch { emit(emptyList()) }
            .combine(userDb.ammoDao().observeAll().catch { emit(emptyList()) }) { builtin, user ->
                (builtin.map { it.toDomain() } + user.map { it.toDomain() })
                    .sortedWith(compareBy({ it.caliber }, { it.name }))
            }

    override suspend fun getCalibers(): List<String> =
        (builtinDb.ammoDao().getCalibers() + userDb.ammoDao().getCalibers())
            .distinct()
            .sorted()

    override suspend fun getByCaliber(caliber: String): List<AmmoLoad> =
        (builtinDb.ammoDao().getByCaliber(caliber) +
         userDb.ammoDao().getByCaliber(caliber))
            .map { it.toDomain() }
            .sortedBy { it.name }

    override suspend fun search(query: String): List<AmmoLoad> =
        (builtinDb.ammoDao().search(query) +
         userDb.ammoDao().search(query))
            .map { it.toDomain() }
            .sortedWith(compareBy({ it.caliber }, { it.name }))

    override suspend fun addUserAmmo(load: AmmoLoad) {
        try {
            userDb.ammoDao().insert(load.toEntity())
        } catch (e: android.database.sqlite.SQLiteConstraintException) {
            throw DuplicateAmmoException(load.name)
        }
    }

    override suspend fun updateUserAmmo(load: AmmoLoad) {
        userDb.ammoDao().update(load.toEntity())
    }

    override suspend fun deleteUserAmmo(id: Int) {
        userDb.ammoDao().deleteById(id)
    }

    private fun AmmoLoad.toEntity() = AmmoEntity(
        id                   = id,
        caliber              = caliber,
        name                 = name,
        velocityFps          = muzzleVelFps,
        bcG1                 = if (bcG1 > 0.0) bcG1 else if (bcModel == BcModel.G1) bc else 0.0,
        bcG7                 = if (bcG7 > 0.0) bcG7 else if (bcModel == BcModel.G7) bc else 0.0,
        formFactor           = formFactor,
        bulletDiameterMm     = bulletDiameterMm,
        bulletLengthMm       = bulletLengthMm,
        bulletWeightGr       = bulletWeightGr,
        mvSensitivityFpsPerF = mvSensitivityFpsPerF,
        mvReferenceTempF     = mvReferenceTempF,
        isUserDefined        = true,
    )
}
