package com.zhentao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhentao.common.PageResult;
import com.zhentao.entity.DynamicFavorites;
import com.zhentao.entity.DynamicLikes;
import com.zhentao.entity.UserDynamics;
import com.zhentao.mapper.DynamicFavoritesMapper;
import com.zhentao.mapper.DynamicLikesMapper;
import com.zhentao.mapper.UserDynamicsMapper;
import com.zhentao.service.InteractionService;
import com.zhentao.vo.DynamicVO;
import com.zhentao.vo.UserSimpleVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class InteractionServiceImpl implements InteractionService {

    @Autowired
    private DynamicLikesMapper likesMapper;
    @Autowired
    private DynamicFavoritesMapper favoritesMapper;
    @Autowired
    private UserDynamicsMapper userDynamicsMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final String LIKE_COUNT_KEY = "dynamic:like:";      // dynamic:like:{dynamicId}
    private static final String FAVORITE_COUNT_KEY = "dynamic:favorite:"; // dynamic:favorite:{dynamicId}
    private static final String LIKE_LOCK_KEY = "lock:dynamic:like:";  // lock:dynamic:like:{userId}:{dynamicId}

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void like(Integer userId, Integer dynamicId) {
        // 使用 Redis 分布式锁防止同一用户快速点击导致的并发问题
        String lockKey = LIKE_LOCK_KEY + userId + ":" + dynamicId;
        Boolean lockAcquired = false;
        try {
            // 尝试获取锁，过期时间 3 秒
            lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(lockAcquired)) {
                // 获取锁失败，说明正在处理中，直接返回
                return;
            }

            // 先检查是否已经点赞
            Long count = likesMapper.selectCount(new QueryWrapper<DynamicLikes>()
                    .eq("user_id", userId)
                    .eq("dynamic_id", dynamicId));
            if (count != null && count > 0) {
                // 已经点赞，直接返回
                return;
            }

            // 幂等：DB唯一索引限制（uk_dynamic_user）
            DynamicLikes like = new DynamicLikes();
            like.setUserId(userId);
            like.setDynamicId(dynamicId);
            like.setCreatedAt(LocalDateTime.now());
            try {
                likesMapper.insert(like);
                // 立即增加缓存计数（Redis不可用时忽略，不影响主流程）
                incrementCacheSafely(LIKE_COUNT_KEY + dynamicId, 1);
                // 可选：同步主表统计（+1）
                userDynamicsMapper.update(null,
                        new com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<UserDynamics>()
                                .eq("dynamic_id", dynamicId)
                                .setSql("like_count = like_count + 1"));
            } catch (DuplicateKeyException ignore) {
                // 已点赞视为成功
            }
        } finally {
            // 释放锁
            if (Boolean.TRUE.equals(lockAcquired)) {
                try {
                    redisTemplate.delete(lockKey);
                } catch (Exception ignore) {
                    // 忽略释放锁失败的异常
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unlike(Integer userId, Integer dynamicId) {
        likesMapper.delete(new QueryWrapper<DynamicLikes>()
                .eq("user_id", userId)
                .eq("dynamic_id", dynamicId));
        // 缓存计数-1（不小于0）
        decrementCacheSafely(LIKE_COUNT_KEY + dynamicId, 1);
        userDynamicsMapper.update(null,
                new com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<UserDynamics>()
                        .eq("dynamic_id", dynamicId)
                        .setSql("like_count = CASE WHEN like_count>0 THEN like_count-1 ELSE 0 END"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void favorite(Integer userId, Integer dynamicId) {
        DynamicFavorites fav = new DynamicFavorites();
        fav.setUserId(userId);
        fav.setDynamicId(dynamicId);
        fav.setCreatedAt(LocalDateTime.now());
        try {
            favoritesMapper.insert(fav);
            incrementCacheSafely(FAVORITE_COUNT_KEY + dynamicId, 1);
            userDynamicsMapper.update(null,
                    new com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<UserDynamics>()
                            .eq("dynamic_id", dynamicId)
                            .setSql("favorite_count = favorite_count + 1"));
        } catch (DuplicateKeyException ignore) {
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unfavorite(Integer userId, Integer dynamicId) {
        favoritesMapper.delete(new QueryWrapper<DynamicFavorites>()
                .eq("user_id", userId)
                .eq("dynamic_id", dynamicId));
        decrementCacheSafely(FAVORITE_COUNT_KEY + dynamicId, 1);
        userDynamicsMapper.update(null,
                new com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<UserDynamics>()
                        .eq("dynamic_id", dynamicId)
                        .setSql("favorite_count = CASE WHEN favorite_count>0 THEN favorite_count-1 ELSE 0 END"));
    }

    @Override
    public PageResult<DynamicVO> listFavorites(Integer userId, Integer pageNum, Integer pageSize) {
        // 查询用户收藏的动态ID列表
        List<Integer> favoriteDynamicIds = favoritesMapper.selectList(new QueryWrapper<DynamicFavorites>()
                .eq("user_id", userId)
                .orderByDesc("created_at"))
                .stream()
                .map(DynamicFavorites::getDynamicId)
                .collect(Collectors.toList());
        
        if (favoriteDynamicIds.isEmpty()) {
            return new PageResult<DynamicVO>(new java.util.ArrayList<>(), 0L, Long.valueOf(pageNum), Long.valueOf(pageSize));
        }
        
        // 查询动态详情（关联用户信息）
        Page<UserDynamics> page = new Page<>(pageNum, pageSize);
        IPage<UserDynamics> pg = userDynamicsMapper.selectDynamicsByIds(page, favoriteDynamicIds, userId);
        
        List<DynamicVO> list = pg.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        return new PageResult<>(list, pg.getTotal(), pg.getCurrent(), pg.getSize());
    }

    @Override
    public PageResult<DynamicVO> listLikedDynamics(Integer userId, Integer pageNum, Integer pageSize) {
        // 查询用户点赞的动态ID列表
        List<Integer> likedDynamicIds = likesMapper.selectList(new QueryWrapper<DynamicLikes>()
                .eq("user_id", userId)
                .orderByDesc("created_at"))
                .stream()
                .map(DynamicLikes::getDynamicId)
                .collect(Collectors.toList());
        
        if (likedDynamicIds.isEmpty()) {
            return new PageResult<DynamicVO>(new java.util.ArrayList<>(), 0L, Long.valueOf(pageNum), Long.valueOf(pageSize));
        }
        
        // 查询动态详情（关联用户信息）
        Page<UserDynamics> page = new Page<>(pageNum, pageSize);
        IPage<UserDynamics> pg = userDynamicsMapper.selectDynamicsByIds(page, likedDynamicIds, userId);
        
        List<DynamicVO> list = pg.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        return new PageResult<>(list, pg.getTotal(), pg.getCurrent(), pg.getSize());
    }
    
    /**
     * 将实体类转换为VO
     */
    private DynamicVO convertToVO(UserDynamics dynamic) {
        DynamicVO vo = new DynamicVO();
        org.springframework.beans.BeanUtils.copyProperties(dynamic, vo);

        // 解析媒体URL JSON字符串
        if (dynamic.getMediaUrls() != null && !dynamic.getMediaUrls().isEmpty()) {
            try {
                List<String> urls = objectMapper.readValue(
                        dynamic.getMediaUrls(), 
                        new TypeReference<List<String>>() {}
                );
                vo.setMediaUrls(urls);
            } catch (Exception e) {
                vo.setMediaUrls(new ArrayList<>());
            }
        } else {
            vo.setMediaUrls(new ArrayList<>());
        }

        // 转换用户信息
        if (dynamic.getUser() != null) {
            UserSimpleVO userVO = new UserSimpleVO();
            userVO.setUserId(dynamic.getUser().getUserId());
            userVO.setNickname(dynamic.getUser().getNickname());
            userVO.setAvatarUrl(dynamic.getUser().getAvatarUrl());
            userVO.setGender(dynamic.getUser().getGender());
            vo.setUser(userVO);
        }

        return vo;
    }

    private void incrementCacheSafely(String key, long delta) {
        try {
            redisTemplate.opsForValue().increment(key, delta);
            redisTemplate.expire(key, 1, TimeUnit.DAYS);
        } catch (Exception ignore) {
            // ignore redis failures
        }
    }

    private void decrementCacheSafely(String key, long delta) {
        try {
            Long v = redisTemplate.opsForValue().increment(key, -Math.abs(delta));
            if (v != null && v < 0) {
                redisTemplate.opsForValue().set(key, 0);
            }
            redisTemplate.expire(key, 1, TimeUnit.DAYS);
        } catch (Exception ignore) {
            // ignore redis failures
        }
    }
}


