package online.wesal.wesal.service;

import online.wesal.wesal.dto.LikedUserDTO;
import online.wesal.wesal.dto.PostResponseDTO;
import online.wesal.wesal.dto.PostWithLikesResponseDTO;
import online.wesal.wesal.entity.Post;
import online.wesal.wesal.entity.PostLike;
import online.wesal.wesal.entity.User;
import online.wesal.wesal.repository.PostLikeRepository;
import online.wesal.wesal.repository.PostRepository;
import online.wesal.wesal.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class PostService {
    
    @Autowired
    private PostRepository postRepository;
    
    @Autowired
    private PostLikeRepository postLikeRepository;
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private UserService userService;
    
    public Post createPost(String body) {
        User currentUser = userService.getCurrentUser();
        Post post = new Post(currentUser.getId(), body);
        return postRepository.save(post);
    }
    
    public List<PostResponseDTO> getAllRecentPosts() {
        LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
        List<Post> posts = postRepository.findAllPostsWithinLast7Days(sevenDaysAgo);
        
        User currentUser = userService.getCurrentUser();
        Long currentUserId = currentUser.getId();
        
        // Get all unique creator IDs
        List<Long> creatorIds = posts.stream()
                .map(Post::getCreatorId)
                .distinct()
                .collect(Collectors.toList());
        
        // Get all post IDs
        List<Long> postIds = posts.stream()
                .map(Post::getId)
                .collect(Collectors.toList());
        
        // Fetch creators in one query
        Map<Long, User> creators = userRepository.findAllById(creatorIds).stream()
                .collect(Collectors.toMap(User::getId, user -> user));
        
        // Fetch user's likes for these posts in one query
        Set<Long> likedPostIds = postLikeRepository.findLikedPostIdsByUserIdAndPostIds(currentUserId, postIds);
        
        return posts.stream()
                .map(post -> new PostResponseDTO(post, creators.get(post.getCreatorId()), 
                     likedPostIds.contains(post.getId())))
                .collect(Collectors.toList());
    }
    
    public List<PostResponseDTO> getUserPosts(Long userId) {
        List<Post> posts = postRepository.findByCreatorIdOrderByCreationDateDesc(userId);
        User creator = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        User currentUser = userService.getCurrentUser();
        Long currentUserId = currentUser.getId();
        
        // Get all post IDs
        List<Long> postIds = posts.stream()
                .map(Post::getId)
                .collect(Collectors.toList());
        
        // Fetch user's likes for these posts in one query
        Set<Long> likedPostIds = postLikeRepository.findLikedPostIdsByUserIdAndPostIds(currentUserId, postIds);
        
        return posts.stream()
                .map(post -> new PostResponseDTO(post, creator, likedPostIds.contains(post.getId())))
                .collect(Collectors.toList());
    }
    
    public PostResponseDTO createPostWithResponse(String body) {
        User currentUser = userService.getCurrentUser();
        Post post = new Post(currentUser.getId(), body);
        post = postRepository.save(post);
        return new PostResponseDTO(post, currentUser, false); // New post is not liked by default
    }
    
    @Transactional
    public PostResponseDTO likePost(Long postId) {
        User currentUser = userService.getCurrentUser();
        Long userId = currentUser.getId();
        
        // Check if post exists
        Post post = postRepository.findById(postId)
                .orElseThrow(() -> new RuntimeException("Post not found"));
        
        // Check if user already liked this post
        if (!postLikeRepository.existsByPostIdAndUserId(postId, userId)) {
            // Add like record
            PostLike postLike = new PostLike(postId, userId);
            postLikeRepository.save(postLike);
            
            // Update post likes count
            post.setLikes(post.getLikes() + 1);
            post = postRepository.save(post);
        }
        
        // Get creator for response
        User creator = userRepository.findById(post.getCreatorId())
                .orElseThrow(() -> new RuntimeException("Creator not found"));
        
        // Check if user now likes this post
        boolean isLiked = postLikeRepository.existsByPostIdAndUserId(postId, userId);
        
        return new PostResponseDTO(post, creator, isLiked);
    }
    
    @Transactional
    public PostResponseDTO unlikePost(Long postId) {
        User currentUser = userService.getCurrentUser();
        Long userId = currentUser.getId();
        
        // Check if post exists
        Post post = postRepository.findById(postId)
                .orElseThrow(() -> new RuntimeException("Post not found"));
        
        // Check if user has liked this post
        if (postLikeRepository.existsByPostIdAndUserId(postId, userId)) {
            // Remove like record
            postLikeRepository.deleteByPostIdAndUserId(postId, userId);
            
            // Update post likes count
            post.setLikes(Math.max(0, post.getLikes() - 1));
            post = postRepository.save(post);
        }
        
        // Get creator for response
        User creator = userRepository.findById(post.getCreatorId())
                .orElseThrow(() -> new RuntimeException("Creator not found"));
        
        // Check if user now likes this post
        boolean isLiked = postLikeRepository.existsByPostIdAndUserId(postId, userId);
        
        return new PostResponseDTO(post, creator, isLiked);
    }
    
    public PostWithLikesResponseDTO getPostById(Long postId) {
        // Get the post
        Post post = postRepository.findById(postId)
                .orElseThrow(() -> new RuntimeException("Post not found"));
        
        // Get the creator
        User creator = userRepository.findById(post.getCreatorId())
                .orElseThrow(() -> new RuntimeException("Creator not found"));
        
        // Get current user to check if they liked the post
        User currentUser = userService.getCurrentUser();
        Long currentUserId = currentUser.getId();
        boolean isLiked = postLikeRepository.existsByPostIdAndUserId(postId, currentUserId);
        
        // Get liked users (limit 100) with their like timestamps
        List<PostLike> postLikes = postLikeRepository.findByPostIdOrderByCreatedAtDesc(postId);
        List<PostLike> limitedPostLikes = postLikes.stream()
                .limit(100)
                .collect(Collectors.toList());
        
        // Get user IDs for batch fetch
        List<Long> likedUserIds = limitedPostLikes.stream()
                .map(PostLike::getUserId)
                .collect(Collectors.toList());
        
        // Batch fetch users
        Map<Long, User> usersMap = userRepository.findAllById(likedUserIds).stream()
                .collect(Collectors.toMap(User::getId, user -> user));
        
        // Create LikedUserDTO list
        List<LikedUserDTO> likedUsers = limitedPostLikes.stream()
                .map(postLike -> new LikedUserDTO(usersMap.get(postLike.getUserId()), postLike.getCreatedAt()))
                .collect(Collectors.toList());
        
        return new PostWithLikesResponseDTO(post, creator, isLiked, likedUsers);
    }
}