package com.myapp.service;

import com.myapp.domain.Micropost;
import com.myapp.domain.User;
import com.myapp.dto.PageParams;
import com.myapp.dto.PostDTO;
import com.myapp.repository.MicropostCustomRepository;
import com.myapp.repository.MicropostRepository;
import com.myapp.repository.UserRepository;
import com.myapp.service.exceptions.NotPermittedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MicropostServiceImpl implements MicropostService {

    private final MicropostRepository micropostRepository;
    private final UserRepository userRepository;
    private final MicropostCustomRepository micropostCustomRepository;
    private final SecurityContextService securityContextService;

    @Autowired
    public MicropostServiceImpl(MicropostRepository micropostRepository, UserRepository userRepository, MicropostCustomRepository micropostCustomRepository, SecurityContextService securityContextService) {
        this.micropostRepository = micropostRepository;
        this.userRepository = userRepository;
        this.micropostCustomRepository = micropostCustomRepository;
        this.securityContextService = securityContextService;
    }

    @Override
    public void delete(Long id) throws NotPermittedException {
        final Micropost micropost = micropostRepository.findOne(id);
        final Optional<User> currentUser = securityContextService.currentUser();

        currentUser.filter(u -> u.equals(micropost.getUser()))
                .ifPresent(u -> micropostRepository.delete(id));
        currentUser.filter(u -> u.equals(micropost.getUser()))
                .orElseThrow(() -> new NotPermittedException("no permission to delete this post"));
    }

    @Override
    public List<PostDTO> findAsFeed(PageParams pageParams) {
        return securityContextService.currentUser()
                .map(u -> micropostCustomRepository.findAsFeed(u, pageParams)
                        .map(toDTO())
                        .collect(Collectors.toList()))
                .orElseThrow(() -> new AccessDeniedException(""));
    }

    @Override
    public List<PostDTO> findByUser(Long userId, PageParams pageParams) {
        final User user = userRepository.findOne(userId);
        return micropostCustomRepository.findByUser(user, pageParams)
                .map(toDTO())
                .collect(Collectors.toList());
    }

    @Override
    public List<PostDTO> findMyPosts(PageParams pageParams) {
        return securityContextService.currentUser()
                .map(u -> findByUser(u.getId(), pageParams))
                .orElseThrow(RuntimeException::new);
    }

    @Override
    public Micropost saveMyPost(Micropost post) {
        return securityContextService.currentUser()
                .map(u -> {
                    post.setUser(u);
                    return micropostRepository.save(post);
                })
                .orElseThrow(() -> new AccessDeniedException(""));
    }

    private Function<MicropostCustomRepository.Row, PostDTO> toDTO() {
        return r -> {
            final Boolean isMyPost = securityContextService.currentUser()
                    .map(u -> r.getMicropost().getUser().equals(u))
                    .orElse(null);
            return PostDTO.newInstance(r.getMicropost(), r.getUserStats(), isMyPost);
        };
    }

}

@@ -3282,24 +3282,106 @@
 %3E toDTO() %7B%0A
+        final Optional%3CUser%3E currentUser = securityContextService.currentUser();%0A%0A
         retu
@@ -3427,39 +3427,16 @@
 yPost = 
-securityContextService.
 currentU
@@ -3430,34 +3430,32 @@
 st = currentUser
-()
 %0A               

fix N+1 query