package com.red.circle.console.app.service.app.user;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.red.circle.console.app.convertor.PropsAppConvertor;
import com.red.circle.console.app.dto.clienobject.user.RunningWaterUserPropsCO;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.inner.endpoint.material.props.PropsRunningWaterClient;
import com.red.circle.other.inner.endpoint.material.props.PropsSourceClient;
import com.red.circle.other.inner.model.cmd.material.RunningWaterUserPropsQryCmd;
import com.red.circle.other.inner.model.dto.material.PropsResourcesDTO;
import com.red.circle.other.inner.model.dto.material.RunningWaterUserPropsDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class RunningWaterUserPropsServiceImpl implements RunningWaterUserPropsService {

  private final UserProfileClient userProfileClient;
  @Qualifier("PropsAppConvertorNew")
  private final PropsAppConvertor propsAppConvertor;
  private final PropsSourceClient propsSourceClient;
  private final PropsRunningWaterClient propsRunningWaterClient;

  @Override
  public PageResult<RunningWaterUserPropsCO> pageRunningWaterUserProps(
      RunningWaterUserPropsQryCmd query) {

    PageResult<RunningWaterUserPropsDTO> getPage = ResponseAssert.requiredSuccess(
        propsRunningWaterClient.pageRunningWaterOps(query));

    if (CollectionUtils.isEmpty(getPage.getRecords())) {
      return getPage.convert(propsAppConvertor::toRunningWaterUserPropsCO);
    }

    Map<Long, UserProfileDTO> userProfileMap = ResponseAssert.requiredSuccess(userProfileClient
        .mapByUserIds(getUserIds(getPage)));

    Map<Long, PropsResourcesDTO> propsSourceRecordMap = ResponseAssert.requiredSuccess(
        propsSourceClient.mapByIds(
            getPage.getRecords().stream().map(RunningWaterUserPropsDTO::getPropsId)
                .collect(Collectors.toSet())
        )
    );

    return getPage.convert(runningWaterUserProps -> {

      RunningWaterUserPropsCO waterUserPropsCO = propsAppConvertor.toRunningWaterUserPropsCO(
          runningWaterUserProps);

      UserProfileDTO buyer = userProfileMap.get(runningWaterUserProps.getCreateUser());
      if (Objects.nonNull(buyer)) {
        waterUserPropsCO.setBuyerUserProfile(buyer);
        waterUserPropsCO.setBuyerId(buyer.getId());
      }

      UserProfileDTO receiver = userProfileMap.get(runningWaterUserProps.getUserId());
      if (Objects.nonNull(receiver)) {
        waterUserPropsCO.setReceiverUserProfile(receiver);
        waterUserPropsCO.setReceiverId(receiver.getId());
      }

      PropsResourcesDTO propsSourceRecordDTO = propsSourceRecordMap
          .get(runningWaterUserProps.getPropsId());
      if (Objects.isNull(propsSourceRecordDTO)) {
        return waterUserPropsCO;
      }
      waterUserPropsCO.setPropsCode(propsSourceRecordDTO.getCode());
      waterUserPropsCO.setPropsCover(propsSourceRecordDTO.getCover());
      waterUserPropsCO.setPropsName(propsSourceRecordDTO.getName());
      waterUserPropsCO.setPropsOrigin(runningWaterUserProps.getOrigin());
      waterUserPropsCO.setPropsOriginDesc(runningWaterUserProps.getOriginDesc());

      return waterUserPropsCO;
    });
  }

  private Set<Long> getUserIds(PageResult<RunningWaterUserPropsDTO> getPage) {
    return Stream
        .of(getPage.getRecords().stream().map(RunningWaterUserPropsDTO::getUserId)
                .collect(Collectors.toSet()),
            getPage.getRecords().stream().map(RunningWaterUserPropsDTO::getCreateUser)
                .collect(Collectors.toSet())).flatMap(Collection::stream)
        .collect(Collectors.toSet());
  }
}
