package de.avatic.lcc.service.access;

import de.avatic.lcc.dto.configuration.material.view.MaterialDetailDTO;
import de.avatic.lcc.dto.generic.MaterialDTO;
import de.avatic.lcc.model.materials.Material;
import de.avatic.lcc.repositories.MaterialRepository;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
import de.avatic.lcc.service.transformer.generic.MaterialTransformer;
import de.avatic.lcc.service.transformer.material.MaterialDetailTransformer;
import de.avatic.lcc.util.exception.badrequest.MaterialNotFoundException;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * Service class responsible for managing materials. Provides functionality to
 * list, retrieve, and manipulate material data. Acts as a bridge between the
 * repository and transformer layers.
 */
@Service
public class MaterialService {

    private final MaterialRepository materialRepository;
    private final MaterialTransformer materialTransformer;
    private final MaterialDetailTransformer materialDetailTransformer;

    /**
     * Constructor for MaterialService.
     *
     * @param materialRepository        repository for accessing material data
     * @param materialTransformer       transformer to convert material entities to DTOs
     * @param materialDetailTransformer transformer to convert material entities to detail DTOs
     */
    public MaterialService(MaterialRepository materialRepository, MaterialTransformer materialTransformer, MaterialDetailTransformer materialDetailTransformer) {
        this.materialRepository = materialRepository;
        this.materialTransformer = materialTransformer;
        this.materialDetailTransformer = materialDetailTransformer;
    }

    /**
     * Lists materials based on a filter and pagination parameters.
     *
     * @param filter the search filter to apply
     * @param page   the page number for pagination (zero-based)
     * @param limit  the maximum number of items per page
     * @return a {@link SearchQueryResult} containing a list of material DTOs and pagination details
     */
    public SearchQueryResult<MaterialDTO> listMaterial(Optional<String> filter, int page, int limit) {
        SearchQueryResult<Material> queryResult = materialRepository.listMaterials(filter, true, new SearchQueryPagination(page, limit));
        return SearchQueryResult.map(queryResult, materialTransformer::toMaterialDTO);
    }

    /**
     * Retrieves the details of a specific material by its ID.
     *
     * @param id the unique identifier of the material
     * @return a {@link MaterialDetailDTO} representing the material details
     * @throws MaterialNotFoundException if no material with the given ID is found
     */
    public MaterialDetailDTO getMaterial(Integer id) {
        return materialDetailTransformer.toMaterialDetailDTO(materialRepository.getById(id).orElseThrow(() -> new NotFoundException(NotFoundException.NotFoundType.MATERIAL,id.toString())));
    }

    /**
     * Updates an existing material with new data.
     *
     * @param id  the ID of the material to update
     * @param dto the data transfer object containing the updated material details
     * @return the ID of the updated material
     * @throws MaterialNotFoundException if no material with the given ID is found
     */
/*    public Integer updateMaterial(Integer id, MaterialUpdateDTO dto) {
        return materialRepository.update(materialUpdateDTOTransformer.fromMaterialUpdateDTO(dto)).orElseThrow(() -> new MaterialNotFoundException(id));
    }*/

    /**
     * Creates a new material based on the provided data.
     *
     * @param dto the data transfer object containing the new material details
     * @return the ID of the newly created material
     * @throws RuntimeException if the material could not be created
     */
/*    public Integer createMaterial(MaterialUpdateDTO dto) {
        return materialRepository.create(materialUpdateDTOTransformer.fromMaterialUpdateDTO(dto)).orElseThrow(() -> new RuntimeException("Unable to create Material " + dto));
    }*/

    /**
     * Marks a material as deprecated by its ID.
     *
     * @param id the ID of the material to deprecate
     * @return the ID of the deprecated material
     * @throws MaterialNotFoundException if no material with the given ID is found
     */
/*    public Integer deleteMaterial(Integer id) {
        return materialRepository.setDeprecatedById(id).orElseThrow(() -> new MaterialNotFoundException(id));
    }*/
}
