package com.apobates.forum.core.impl.service;

import com.apobates.forum.attention.ImageDirectoryEnum;
import com.apobates.forum.attention.core.UploadImagePathConvert;
import com.apobates.forum.core.ImageIOMeta;
import com.apobates.forum.core.dao.AlbumDao;
import com.apobates.forum.core.dao.AlbumPictureDao;
import com.apobates.forum.core.entity.Album;
import com.apobates.forum.core.entity.AlbumPicture;
import com.apobates.forum.core.entity.Board;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.proxy.AlbumReplica;
import com.apobates.forum.core.service.AlbumService;
import com.apobates.forum.core.service.BoardService;
import com.apobates.forum.utils.persistence.Page;
import com.apobates.forum.utils.persistence.Pageable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 * @author xiaofanku
 * @since 20200512
 */
@Service
public class AlbumServiceImpl implements AlbumService{
    @Autowired
    private AlbumDao albumDao;
    @Autowired
    private AlbumPictureDao albumPictureDao;
    @Autowired
    private BoardService boardService;
    private final static Logger logger = LoggerFactory.getLogger(AlbumServiceImpl.class);

    @Override
    public Optional<Boolean> editCover(long id, long pictureId)throws IllegalArgumentException,IllegalStateException {
        AlbumPicture data = albumPictureDao.findOne(pictureId).orElseThrow(()->new IllegalArgumentException("图片不存在或暂时无法访问"));
        if (!data.isStatus()) {
            throw new IllegalStateException("图片已被禁止访问");
        }
        return albumDao.editCover(id, data.getLink(), data.getId());
    }
    
    @Override
    public long create(String encodeImageAddr, String caption, boolean status, Topic topic)throws IllegalArgumentException {
        if (null == encodeImageAddr || encodeImageAddr.isEmpty()) {
            throw new IllegalArgumentException("图片地址不可用或不被接受");
        }
        if(null == topic){
            throw new IllegalArgumentException("话题不存在或暂时无法访问");
        }
        AlbumPicture ap = new AlbumPicture();
        ap.setStatus(status);
        ap.setLink(encodeImageAddr);
        ap.setCaption(caption);
        
        Album album = new Album(
                topic.getTitle(),
                topic.getVolumesId(),
                topic.getBoardId(),
                topic.getId(),
                topic.getMemberId(),
                topic.getMemberNickname(),
                List.of(ap));
        ap.setAlbum(album);
        try {
            albumDao.save(album);
            if (album.getId() > 0) {
                return album.getId();
            }
        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.debug(e.getMessage(), e);
            }
        }
        return 0L;//("像册创建失败");
    }
    
    @Override
    public Stream<AlbumReplica> getRecent(final int size) { 
        /*
        List<Album> data = albumDao.findAllRecent(size).collect(Collectors.toList());
        if (data.isEmpty()) {
            return Stream.empty();
        }
        Set<Long> boardIdSet = data.stream().map(Album::getBoardId).collect(Collectors.toSet());
        Map<Long, String> boardTitleMap = boardService.getAllById(boardIdSet);
        //
        Consumer<AlbumReplica> action = ar->{
            String boardTitle = boardTitleMap.get(ar.getBoardId());
            Board b = new Board();
                b.setId(ar.getBoardId());
                b.setTitle(boardTitle);
                b.setVolumesId(ar.getVolumesId());
            ar.setBoard(b);
        };
        return data.stream().map(AlbumReplica.copyAlbum).peek(action);*/
        final BiFunction<Album, String, AlbumReplica> action = (album, boardTitle)->{
            AlbumReplica ar = Optional.ofNullable(album).map(AlbumReplica.copyAlbum).orElseGet(AlbumReplica::new);
            Board b = new Board();
                b.setId(album.getBoardId());
                b.setTitle(boardTitle);
                b.setVolumesId(album.getVolumesId());
            ar.setBoard(b);
            return ar;
        };
        return CompletableFuture.supplyAsync(()->albumDao.findAllRecent(size))
                .thenApply((Stream<Album> data)->data.collect(Collectors.toMap(Function.identity(), Album::getBoardId)))
                .thenCompose((Map<Album,Long> amap)->
                        CompletableFuture.supplyAsync(()->boardService.getAllById(amap.values()))
                                .completeOnTimeout(Collections.emptyMap(), 1, TimeUnit.SECONDS)
                                .thenApply((Map<Long, String> boardTitleMap)->{
                                    return amap.keySet().stream().map(a->action.apply(a, boardTitleMap.get(a.getBoardId())));
                                })).orTimeout(1, TimeUnit.SECONDS).join();
    }
    
    @Override
    public Stream<Album> getAll(final Set<Long> topicIdSet, final ImageIOMeta imageIO, final String scale, final String defaultPicture) {
        if (null == topicIdSet || topicIdSet.isEmpty()) {
            return Stream.empty();
        }
        List<Long> topicIds = topicIdSet.stream().filter(topicId -> topicId > 0).collect(Collectors.toList());
        //上传图片的路径转换
        final UploadImagePathConvert uipc = new UploadImagePathConvert(imageIO.getImageBucketDomain(), imageIO.getUploadImageDirectName());
        Consumer<Album> action = album->{
            try {
                String imagePath = uipc
                        .decode(album.getCoverLink(), ImageDirectoryEnum.DEFAT, scale)
                        .map(URL::toString)
                        .orElse(defaultPicture); //"/static/img/140x140.png"
                album.setCoverLink(imagePath);
            }catch (MalformedURLException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug(String.format("%s is malformed fail", album.getCoverLink()), ex);
                }
            }
        };
        return albumDao.findAllByTopic(topicIds).peek(action);
    }
    
    @Override
    public Page<Album> getAll(Pageable pageable) {
        return albumDao.findAll(pageable);
    }
    
    @Override
    public Page<Album> getAll(int volumesId, Pageable pageable) {
        return albumDao.findAllByVolumes(volumesId, pageable);
    }
    
    @Override
    public Page<Album> getAll(long boardId, Pageable pageable) {
        return albumDao.findAllByBoard(boardId, pageable);
    }
    
    @Override
    public Optional<Album> getByTopic(long topicId) {
        return albumDao.findOneByTopic(topicId);
    }
    
    @Override
    public Optional<Album> get(long id) {
        if(id > 0){
            return albumDao.findOne(id);
        }
        return Optional.empty();
    }
}