package cz.muni.fi.pa165.core.common;

import cz.muni.fi.pa165.core.helpers.exceptions.EntityDeletionException;
import cz.muni.fi.pa165.model.dto.common.DomainObjectDto;
import cz.muni.fi.pa165.model.dto.common.Result;
import org.springframework.data.domain.Pageable;

import java.util.List;

/**
 * Abstract class that serves as a facade for accessing and manipulating data
 * using a {@link DomainService} and a {@link DomainMapper}.
 *
 * @param <E> the Entity type representing the object
 * @param <T> the DTO type representing the entity being manipulated
 * @param <C> the DTO type representing a create operation for the entity
 * @param <U> the DTO type representing an update operation for the entity
 */
public abstract class DomainFacade<E extends DomainObject,
		T extends DomainObjectDto,
		C extends DomainObjectDto,
		U extends DomainObjectDto> {

	/**
	 * The service used to perform CRUD operations on the entity.
	 */
	private final DomainService<E> service;

	/**
	 * The mapper used to convert between entity and DTO representations.
	 */
	protected final DomainMapper<E, T, C, U> mapper;

	/**
	 * Constructs a new {@code DomainFacade} with the given {@code DomainService} and {@code DomainMapper}.
	 *
	 * @param service the service to be used for CRUD operations
	 * @param mapper the mapper to be used for entity-DTO conversions
	 */
	protected DomainFacade(DomainService<E> service, DomainMapper<E, T, C, U> mapper) {
		this.service = service;
		this.mapper = mapper;
	}

	/**
	 * Finds an entity by its ID and returns its DTO representation.
	 *
	 * @param id the ID of the entity to find
	 * @return the DTO representation of the found entity
	 */
	public T findById(String id) {
		return mapper.toDto(service.findById(id));
	}

	/**
	 * Finds all entities in pageable format and returns their DTO representations.
	 *
	 * @param pageable the pagination information
	 * @return a list of DTO representations of the found entities
	 */
	public Result<T> findAllPageable(Pageable pageable) {
		return mapper.toResult(service.findAllPageable(pageable));
	}

	/**
	 * Finds all entities and returns them in a {@link Result} object containing pagination and entity information.
	 *
	 * @param page the page number to retrieve
	 * @return a {@code Result} object containing pagination and entity information
	 */
	public Result<T> findAll(int page) {
		return mapper.toResult(service.findAllPageableInt(page));
	}


	/**
	 * Finds all entities and returns their DTO representations.
	 *
	 * @return a list of DTO representations of the found entities
	 */
	public List<T> findAll() {
		return mapper.toDtoList(service.findAll());
	}

	/**
	 * Creates a new entity using the given DTO representation of a create operation and returns its DTO representation.
	 *
	 * @param createDto the DTO representation of the create operation for the entity
	 * @return the DTO representation of the created entity
	 */
	public T create(C createDto) {
		return mapper.toDto(service.create(mapper.fromCreateDto(createDto)));
	}

	/**
	 * Updates an entity by its ID.
	 *
	 * @param updateDto DTO with updated entity data.
	 * @param id        ID of the entity to be updated.
	 * @return DTO representing the updated entity.
	 */
	public T updateById(U updateDto, String id) {
		return mapper.toDto(service.update(mapper.fromUpdateDto(updateDto), id));
	}

	/**
	 * Deletes an entity by its ID.
	 *
	 * @param id	ID of the entity to be deleted.
	 * @return DTO representing the deleted entity.
	 */
	public T deleteById(String id) throws EntityDeletionException {
		return mapper.toDto(service.deleteById(id));
	}
}