package dev.fyloz.trial.colorrecipesexplorer.service

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.repository.MixTypeRepository
import org.springframework.context.annotation.Lazy
import org.springframework.stereotype.Service

interface MixTypeService : NamedModelService<MixType, MixTypeRepository> {
    /** Gets the mix type with the given [material]. */
    fun getByMaterial(material: Material): MixType

    /** Returns a new and persisted [MixType] with the given [name] and [materialType]. */
    fun createForNameAndMaterialType(name: String, materialType: MaterialType): MixType

    /** Returns the given [mixType] updated with the given [name] and [materialType]. */
    fun updateForNameAndMaterialType(mixType: MixType, name: String, materialType: MaterialType): MixType
}

@Service
class MixTypeServiceImpl(
    mixTypeRepository: MixTypeRepository,
    @Lazy val materialService: MaterialService,
    @Lazy val mixService: MixService
) :
    AbstractNamedModelService<MixType, MixTypeRepository>(mixTypeRepository), MixTypeService {
    override fun getByMaterial(material: Material): MixType =
        repository.findByMaterial(material) ?: throw EntityNotFoundRestException(material.name)

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

    override fun createForNameAndMaterialType(name: String, materialType: MaterialType): MixType =
        save(
            mixType(
                name = name,
                material = material(
                    name = name,
                    inventoryQuantity = Float.MIN_VALUE,
                    isMixType = true,
                    materialType = materialType
                )
            )
        )

    override fun updateForNameAndMaterialType(mixType: MixType, name: String, materialType: MaterialType): MixType =
        update(mixType.apply {
            this.name = name
            material.name = name
            material.materialType = materialType
        })
}
