package dev.fyloz.trial.colorrecipesexplorer.service

import dev.fyloz.trial.colorrecipesexplorer.repository.MaterialRepository
import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsRestException
import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundRestException
import dev.fyloz.trial.colorrecipesexplorer.model.*
import dev.fyloz.trial.colorrecipesexplorer.service.files.SimdutService
import dev.fyloz.trial.colorrecipesexplorer.service.model.MixQuantityService
import io.jsonwebtoken.lang.Assert
import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Service

interface MaterialService : NamedModelService<Material, MaterialSaveDto, MaterialUpdateDto, MaterialRepository> {
    /** Checks if a material with the given [materialType] exists. */
    fun existsByMaterialType(materialType: MaterialType): Boolean

    /** Checks if the given [material] is used by at least one mix. */
    fun isLinkedToMixes(material: Material): Boolean

    /** Gets all materials that are not a mix type. */
    fun getAllNotMixType(): Collection<Material>
}

@Service
class MaterialServiceImpl(materialRepository: MaterialRepository, val mixQuantityService: MixQuantityService, val simdutService: SimdutService) :
        AbstractNamedModelService<Material, MaterialSaveDto, MaterialUpdateDto, MaterialRepository>(materialRepository),
        MaterialService {
    override fun existsByMaterialType(materialType: MaterialType): Boolean = repository.existsByMaterialType(materialType)
    override fun isLinkedToMixes(material: Material): Boolean = mixQuantityService.existsByMaterial(material)
    override fun getAllNotMixType(): Collection<Material> = getAll().filter { !it.isMixType }

    override fun save(entity: MaterialSaveDto): Material =
            save(entity.toMaterial()).apply {
                if (entity.simdutFile != null && !entity.simdutFile.isEmpty) simdutService.write(this, entity.simdutFile)
            }

    override fun save(entity: Material): Material {
        if (existsByName(entity.name))
            throw EntityAlreadyExistsRestException(entity.name)
        return super.save(entity)
    }

    override fun update(entity: MaterialUpdateDto): Material =
            update(entity.toMaterial()).apply { simdutService.update(entity.simdutFile, this) }

    override fun update(entity: Material): Material {
        Assert.notNull(entity.id, "MaterialService.update() was called with a null identifier")
        val persistedMaterial = getById(entity.id!!)
        Assert.notNull(persistedMaterial.materialType, "A persisted material has a null material type")

        return super.update(with(entity) {
            material(
                    id = id!!,
                    name = if (name.isNotBlank()) name else persistedMaterial.name,
                    inventoryQuantity = if (inventoryQuantity != Float.MIN_VALUE) inventoryQuantity else persistedMaterial.inventoryQuantity,
                    isMixType = persistedMaterial.isMixType,
                    materialType = if (materialType != null) materialType!! else persistedMaterial.materialType!!
            )
        })
    }
}
