package dp.kotul.templategroupsbackend.facade

import dp.kotul.solrapimodel.solrsearch.AssetType
import dp.kotul.solrapimodel.solrsearch.SolrUtils
import dp.kotul.starter.service.AuthorizationService
import dp.kotul.templategroupsbackend.helper.SolrSearchHelper
import dp.kotul.templategroupsbackend.model.entity.TemplateGroup
import dp.kotul.templategroupsbackend.model.entity.TemplateGroupVariable
import dp.kotul.templategroupsbackend.model.entity.TemplateVariable
import dp.kotul.templategroupsbackend.model.entity.VariableSourceType
import dp.kotul.templategroupsbackend.model.response.TemplateGroupVariableRequestResponse
import dp.kotul.templategroupsbackend.repository.TemplateGroupRepository
import dp.kotul.templategroupsbackend.repository.TemplateGroupVariableRepository
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
import javax.persistence.EntityManager

interface TemplateGroupVariableFacade {
    fun getTemplateGroupVariables(templateGroupId: Int, laeId: Int?): List<TemplateGroupVariableRequestResponse>
    fun updateTemplateGroupVariables(templateGroupId: Int, templateGroupVariablesRequest: List<TemplateGroupVariableRequestResponse>): List<TemplateGroupVariable>
}

@Component
@Transactional
class TemplateGroupVariableFacadeImpl(
        val authService: AuthorizationService,
        val entityManager: EntityManager,
        val templateGroupRepository: TemplateGroupRepository,
        val templateGroupVariableRepository: TemplateGroupVariableRepository,
        val solrSearchHelper: SolrSearchHelper,
) : TemplateGroupVariableFacade {

    override fun getTemplateGroupVariables(templateGroupId: Int, laeId: Int?): List<TemplateGroupVariableRequestResponse> {
        val user = authService.getUser()
        val languageId = laeId ?: user.laeId

        val templateGroup = templateGroupRepository.findByIdOrNull(templateGroupId) ?: return emptyList()

        if (templateGroup.templateGroupVariables.isNullOrEmpty()) {
            return emptyList()
        }

        val solrTemplatesResponse = solrSearchHelper.getSolrTemplatesResponse(languageId, templateGroup.templates) ?: return emptyList()

        val templateGroupVariables = templateGroup.templateGroupVariables

        val templateVariablesWithSourceTypeTemplate = templateGroup.templates.flatMap { template ->
            template.templateVariables.filter { it.variableSource?.sourceType == VariableSourceType.TEMPLATE }
        }

        val solrTemplates = solrTemplatesResponse.templates

        val templateVariables = templateGroup.templates.flatMap { template -> template.templateVariables.map { it }  }

        val templateVariablesIdsWithMandatoryExt = solrTemplates.flatMap { templateSolr ->
            templateSolr.templateVariables.filter { it.mandatoryExt }.map { templateVariableSolr ->
                templateVariables.first { templateSolr.id == SolrUtils.getUniqueSolrDocumentId(it.template.templateExtId,
                    AssetType.TEMPLATE, it.template.templateType.name, languageId) && templateVariableSolr.templateVariableExtId == it.templateVariableExtId } }.map { it.templateVariableId }
        }

        return templateGroupVariables.map { templateGroupVariable ->
            val templateSolr = solrTemplates.first { it.id == SolrUtils.getUniqueSolrDocumentId(templateGroupVariable.templateVariable.template.templateExtId,
                AssetType.TEMPLATE, templateGroupVariable.templateVariable.template.templateType.name, languageId) }

            val templateGroupVariableSolr = templateSolr.templateVariables.first { templateGroupVariable.templateVariable.templateVariableExtId == it.templateVariableExtId }

            var shouldBeMandatory = templateGroupVariableSolr.mandatoryExt

            if (templateVariablesWithSourceTypeTemplate.isNotEmpty()) {
                val templateVariableWithSourceTypeTemplate = templateVariablesWithSourceTypeTemplate.filter { templateGroupVariable.templateVariable.templateVariableId.toString() == it.variableSource?.sourceFieldId }
                        .map { it.templateVariableId }

                if(templateVariableWithSourceTypeTemplate.isNotEmpty()) {
                    shouldBeMandatory = templateVariablesIdsWithMandatoryExt.any { templateVariableIdMandatoryExt ->
                        templateVariableWithSourceTypeTemplate.contains(templateVariableIdMandatoryExt)
                    }
                }
            }

            TemplateGroupVariableRequestResponse(
                    templateGroupVariableId = templateGroupVariable.templateGroupVariableId,
                    templateVariableId = templateGroupVariable.templateVariable.templateVariableId,
                    templateName = templateSolr.name,
                    name = templateGroupVariable.name!!,
                    defaultValue = templateGroupVariable.defaultValue,
                    sortOrder = templateGroupVariable.sortOrder,
                    mandatory = if(shouldBeMandatory) true else templateGroupVariable.mandatory,
                    mandatoryExt = shouldBeMandatory)
        }.sortedBy { it.sortOrder }
    }

    override fun updateTemplateGroupVariables(templateGroupId: Int, templateGroupVariablesRequest: List<TemplateGroupVariableRequestResponse>): List<TemplateGroupVariable> {
        val templateGroupVariables = templateGroupVariablesRequest.map { templateGroupVariableRequest ->
            TemplateGroupVariable(
                    templateGroupVariableId = templateGroupVariableRequest.templateGroupVariableId,
                    name = templateGroupVariableRequest.name,
                    defaultValue = templateGroupVariableRequest.defaultValue,
                    mandatory = templateGroupVariableRequest.mandatory,
                    sortOrder = templateGroupVariableRequest.sortOrder,
                    templateGroup = entityManager.getReference(TemplateGroup::class.java, templateGroupId),
                    templateVariable = entityManager.getReference(TemplateVariable::class.java, templateGroupVariableRequest.templateVariableId))
        }

        return templateGroupVariableRepository.saveAll(templateGroupVariables)
    }
}
