package com.tomhempel.rbarometer.questionnaire

import android.content.Context
import com.tomhempel.rbarometer.LanguageManager
import com.tomhempel.rbarometer.MyApp
import com.tomhempel.rbarometer.data.Answer
import com.tomhempel.rbarometer.data.AnswerRepository
import com.tomhempel.rbarometer.data.ClientAnswersCache
import com.tomhempel.rbarometer.data.ClientRepository
import com.tomhempel.rbarometer.data.CompletedQuestionnaireRepository
import com.tomhempel.rbarometer.data.CompletedQuestionnaire
import com.tomhempel.rbarometer.data.Question
import com.tomhempel.rbarometer.data.Questionnaire
import com.tomhempel.rbarometer.network.SyncLog
import com.tomhempel.rbarometer.notification.UploadReminderScheduler

object QuestionnairePersistence {

    suspend fun saveAnswers(
        context: Context,
        answers: Map<String, Any>,
        questionnaireId: String,
        languageId: String,
        questions: List<QuestionItem> = emptyList(),
    ) {
        val persistedAnswers = canonicalPersistedAnswers(answers, questions)
        SyncLog.d("QUESTIONNAIRE", "Persisting ${persistedAnswers.size} answer field(s)")
        if (!ClientAssignmentGuard.canPersistAnswers(context, answers)) {
            val clientCode = answers["client_code"] as? String
            SyncLog.w("QUESTIONNAIRE", "Skipping save for unassigned ${SyncLog.clientRef(clientCode)}")
            return
        }

        val clientCode = answers["client_code"] as? String ?: return
        val db = MyApp.database

        ClientRepository.ensureClient(clientCode)
        db.questionnaireDao().insertQuestionnaire(Questionnaire(id = questionnaireId))

        AnswerRepository.deleteAnswersForClientAndQuestionnaire(clientCode, questionnaireId)

        val questionEntities = persistedAnswers.keys
            .filterNot { it.startsWith("client") }
            .map { key ->
                Question(
                    questionId = AnswerKeyUtils.roomQuestionId(questionnaireId, key),
                    questionnaireId = questionnaireId,
                    question = LanguageManager.getText(languageId, key),
                )
            }
        db.questionDao().insertQuestions(questionEntities)

        val answerEntities = persistedAnswers.entries
            .filterNot { it.key.startsWith("client") }
            .map { (key, value) ->
                Answer(
                    clientCode = clientCode,
                    questionId = AnswerKeyUtils.roomQuestionId(questionnaireId, key),
                    answerValue = value.toString(),
                )
            }
        AnswerRepository.insertAnswers(answerEntities)
        ClientAnswersCache.invalidate(clientCode)

        CompletedQuestionnaireRepository.insert(
            CompletedQuestionnaire(
                clientCode = clientCode,
                questionnaireId = questionnaireId,
                isDone = true,
                sumPoints = null,
            ),
        )
        UploadReminderScheduler.schedule(context)
    }

    /** Persists partial answers without marking the questionnaire complete (for session pause/resume). */
    suspend fun saveDraftAnswers(
        context: Context,
        answers: Map<String, Any>,
        questionnaireId: String,
        languageId: String,
        questions: List<QuestionItem> = emptyList(),
    ) {
        if (answers.isEmpty()) return
        val persistedAnswers = canonicalPersistedAnswers(answers, questions)
        if (persistedAnswers.isEmpty()) return
        SyncLog.d("QUESTIONNAIRE", "Persisting draft ${persistedAnswers.size} answer field(s)")
        if (!ClientAssignmentGuard.canPersistAnswers(context, answers)) {
            val clientCode = answers["client_code"] as? String
            SyncLog.w("QUESTIONNAIRE", "Skipping draft save for unassigned ${SyncLog.clientRef(clientCode)}")
            return
        }

        val clientCode = answers["client_code"] as? String ?: return
        val existing = CompletedQuestionnaireRepository.getStatus(clientCode, questionnaireId)
        if (existing?.isDone == true) {
            SyncLog.d("QUESTIONNAIRE", "Skipping draft save — questionnaire already completed")
            return
        }

        val db = MyApp.database
        ClientRepository.ensureClient(clientCode)
        db.questionnaireDao().insertQuestionnaire(Questionnaire(id = questionnaireId))

        AnswerRepository.deleteAnswersForClientAndQuestionnaire(clientCode, questionnaireId)

        val questionEntities = persistedAnswers.keys
            .filterNot { it.startsWith("client") }
            .map { key ->
                Question(
                    questionId = AnswerKeyUtils.roomQuestionId(questionnaireId, key),
                    questionnaireId = questionnaireId,
                    question = LanguageManager.getText(languageId, key),
                )
            }
        db.questionDao().insertQuestions(questionEntities)

        val answerEntities = persistedAnswers.entries
            .filterNot { it.key.startsWith("client") }
            .map { (key, value) ->
                Answer(
                    clientCode = clientCode,
                    questionId = AnswerKeyUtils.roomQuestionId(questionnaireId, key),
                    answerValue = value.toString(),
                )
            }
        AnswerRepository.insertAnswers(answerEntities)
        ClientAnswersCache.invalidate(clientCode)
    }

    private fun canonicalPersistedAnswers(
        answers: Map<String, Any>,
        questions: List<QuestionItem>,
    ): Map<String, Any> {
        if (questions.isEmpty()) return answers

        val filtered = answers.toMutableMap()
        for (question in questions) {
            val canonicalKey = answerKeyFor(question) ?: continue
            val shortId = question.id.takeIf { it.isNotBlank() && it != canonicalKey } ?: continue
            filtered.remove(shortId)
        }
        return filtered
    }

    private fun answerKeyFor(question: QuestionItem): String? = when (question) {
        is QuestionItem.RadioQuestion -> question.question ?: question.id
        is QuestionItem.MultiCheckboxQuestion -> question.question.ifBlank { question.id }
        is QuestionItem.StringSpinnerQuestion -> question.question.ifBlank { question.id }
        is QuestionItem.ValueSpinnerQuestion -> question.question.ifBlank { question.id }
        is QuestionItem.FreeTextQuestion -> question.question.ifBlank { question.id }
        is QuestionItem.DateSpinnerQuestion -> question.question.ifBlank { question.id }
        is QuestionItem.SliderQuestion -> question.question.ifBlank { question.id }
        is QuestionItem.ClientCoachCodeQuestion -> null
        is QuestionItem.GlassScaleQuestion -> null
        is QuestionItem.LastPage -> null
    }
}
