package com.tomhempel.rbarometer.data

import com.tomhempel.rbarometer.MyApp
import com.tomhempel.rbarometer.security.SensitiveDataCrypto
object CompletedQuestionnaireRepository {

    private val dao get() = MyApp.database.completedQuestionnaireDao()

    private fun key(clientCode: String) = SensitiveDataCrypto.clientCodeKey(clientCode)

    suspend fun insert(entry: CompletedQuestionnaire) {
        dao.insert(entry.toEntity())
    }

    suspend fun insertAll(entries: List<CompletedQuestionnaire>) {
        if (entries.isEmpty()) return
        dao.insertAll(entries.map { it.toEntity() })
    }

    suspend fun getStatus(clientCode: String, questionnaireId: String): CompletedQuestionnaire? =
        dao.getStatus(key(clientCode), questionnaireId)?.toDomain(clientCode)

    suspend fun getAllForClient(clientCode: String): List<CompletedQuestionnaire> =
        dao.getAllForClient(key(clientCode)).map { it.toDomain(clientCode) }

    /** One query for many clients (bulk answer import prep). */
    suspend fun getAllGroupedByClient(clientCodes: List<String>): Map<String, List<CompletedQuestionnaire>> {
        if (clientCodes.isEmpty()) return emptyMap()
        val keyToCode = clientCodes.associateBy { key(it) }
        val grouped = mutableMapOf<String, MutableList<CompletedQuestionnaire>>()
        for (entity in dao.getAllForClients(keyToCode.keys.toList())) {
            val code = keyToCode[entity.clientCodeKey] ?: continue
            grouped.getOrPut(code) { mutableListOf() }.add(entity.toDomain(code))
        }
        return grouped
    }

    suspend fun getCompletedQuestionnaireIds(clientCode: String): List<String> =
        dao.getCompletedQuestionnairesForClient(key(clientCode))

    suspend fun getPendingUploadForClient(clientCode: String): List<CompletedQuestionnaire> =
        dao.getPendingUploadForClient(key(clientCode)).map { it.toDomain(clientCode) }

    suspend fun getAllPendingUploads(): List<CompletedQuestionnaire> {
        val keyToCode = ClientRepository.getAllClientCodes().associateBy { SensitiveDataCrypto.clientCodeKey(it) }
        return dao.getAllPendingUploads().mapNotNull { entity ->
            val code = keyToCode[entity.clientCodeKey] ?: return@mapNotNull null
            entity.toDomain(code)
        }
    }

    suspend fun countPendingUploads(): Int = dao.countAllPendingUploads()

    suspend fun markUploaded(clientCode: String, questionnaireId: String, uploadedAt: Long) {
        dao.markUploaded(key(clientCode), questionnaireId, uploadedAt)
    }

    private fun CompletedQuestionnaire.toEntity() = CompletedQuestionnaireEntity(
        clientCodeKey = key(clientCode),
        questionnaireId = questionnaireId,
        timestamp = timestamp,
        isDone = isDone,
        sumPoints = sumPoints,
        uploadedAt = uploadedAt,
    )

    private fun CompletedQuestionnaireEntity.toDomain(clientCode: String) = CompletedQuestionnaire(
        clientCode = clientCode,
        questionnaireId = questionnaireId,
        timestamp = timestamp,
        isDone = isDone,
        sumPoints = sumPoints,
        uploadedAt = uploadedAt,
    )
}
