package com.oguerreiro.resilient.service.mapper;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Named;

import com.oguerreiro.resilient.domain.Period;
import com.oguerreiro.resilient.domain.PeriodVersion;
import com.oguerreiro.resilient.service.dto.PeriodDTO;
import com.oguerreiro.resilient.service.dto.PeriodVersionDTO;

/**
 * Mapper for the entity {@link Period} and its DTO {@link PeriodDTO}.
 */
@Mapper(componentModel = "spring")
public interface PeriodMapper extends ResilientEntityMapper<PeriodDTO, Period> {
  @Mapping(target = "periodVersions", source = "periodVersions", qualifiedByName = "periodVersionNameList")
  PeriodDTO toDto(Period s);

  @Mapping(target = "removePeriodVersion", ignore = true)
  Period toEntity(PeriodDTO periodDTO);

  @Named("periodVersionPropertyName")
  @BeanMapping(ignoreByDefault = true)
  @Mapping(target = "id", source = "id")
  @Mapping(target = "name", source = "name")
  @Mapping(target = "description", source = "description")
  @Mapping(target = "periodVersion", source = "periodVersion")
  @Mapping(target = "state", source = "state")
  @Mapping(target = "version", source = "version")
  PeriodVersionDTO toDtoPeriodVersionPropertyName(PeriodVersion periodVersion);

  @Named("periodVersionNameList")
  default List<PeriodVersionDTO> toDtoPeriodVersionPropertyNameSet(List<PeriodVersion> periodVersion) {
    return periodVersion.stream().map(this::toDtoPeriodVersionPropertyName).collect(Collectors.toList());
  }

  /* ********************************************************************* */
  /* MAPPER for update. Restricts to client side updatable properties only */
  /* ********************************************************************* */

  /**
   * {@link PeriodDTO} to {@link Period} updating an existing instance of {@link Period} using concurrency check.<br>
   * ATTENTION: This is just half of the solution. The nested collection (PeriodVersion's) is to complex to be done by
   * the mapper.
   * The solution is in the PeriodService.update()
   * 
   * @param periodDTO
   * @param period
   */
  @Mapping(target = "removePeriodVersion", ignore = true)
  @Mapping(target = "state", ignore = true)
  @Mapping(target = "creationDate", ignore = true)
  @Mapping(target = "creationUsername", ignore = true)
  @Mapping(target = "periodVersions", ignore = true)	//Will be managed manually in PeriodService.updateSafe()
  void updatePeriodFromDto(PeriodDTO periodDTO, @MappingTarget Period period);

  @Mapping(target = "state", ignore = true)
  @Mapping(target = "creationDate", ignore = true)
  @Mapping(target = "creationUsername", ignore = true)
  PeriodVersion toPeriodVersion(PeriodVersionDTO dto);

  @Named("periodVersionMap")
  default List<PeriodVersion> toEntityPeriodVersionsSet(List<PeriodVersionDTO> dtos) {
    if (dtos == null)
      return Collections.emptyList();
    return dtos.stream().map(this::toPeriodVersion).collect(Collectors.toList());
  }
}
