package com.test.musichouduan.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import com.test.musichouduan.dto.*;
import com.test.musichouduan.entity.User;
import com.test.musichouduan.repository.*;
import com.test.musichouduan.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserCollectMusicRepository userCollectMusicRepository;

    @Autowired
    private UserCollectPlaylistRepository userCollectPlaylistRepository;

    @Autowired
    private UserCollectSingerRepository userCollectSingerRepository;

    @Autowired
    private PlaylistRepository playlistRepository;

    @Override
    @Transactional
    public UserDTO register(RegisterRequest request) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }

        // 检查两次密码是否一致
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            throw new RuntimeException("两次密码不一致");
        }

        // 创建用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setPassword(BCrypt.hashpw(request.getPassword()));
        user.setEmail(request.getEmail());
        user.setNickname(request.getNickname() != null ? request.getNickname() : request.getUsername());
        user.setGender(0);
        user.setRole(0);
        user.setStatus(1);

        // 保存用户
        user = userRepository.save(user);

        // 返回用户DTO
        return convertToDTO(user);
    }

    @Override
    public LoginResultDTO login(LoginRequest request) {
        // 根据用户名查找用户
        User user = userRepository.findByUsername(request.getUsername())
                .orElseThrow(() -> new RuntimeException("用户名或密码错误"));

        // 检查用户状态
        if (user.getStatus() == 0) {
            throw new RuntimeException("账号已被禁用");
        }

        // 检查密码
        if (!BCrypt.checkpw(request.getPassword(), user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 登录
        StpUtil.login(user.getId());

        // 设置角色
        if (user.getRole() == 1) {
            // 打印调试信息
            System.out.println("设置用户ID: " + user.getId() + " 为admin角色");
        }

        // 获取令牌信息
        String token = StpUtil.getTokenValue();
        String tokenName = StpUtil.getTokenName();

        // 创建登录结果DTO
        LoginResultDTO resultDTO = new LoginResultDTO();
        resultDTO.setUser(convertToDTO(user));
        resultDTO.setToken(token);
        resultDTO.setTokenName(tokenName);
        resultDTO.setTokenPrefix("");

        // 返回登录结果DTO
        return resultDTO;
    }

    @Override
    public UserDTO getCurrentUser() {
        // 获取当前登录用户ID
        Long userId = StpUtil.getLoginIdAsLong();

        // 根据ID查找用户
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 返回用户DTO
        return getUserStats(userId);
    }

    @Override
    public UserDTO getUserById(Long id) {
        // 根据ID查找用户
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 返回用户DTO
        return convertToDTO(user);
    }

    @Override
    public UserDTO getUserByUsername(String username) {
        // 根据用户名查找用户
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 返回用户DTO
        return convertToDTO(user);
    }

    @Override
    @Transactional
    public UserDTO updateUser(UserUpdateRequest request) {
        // 获取当前登录用户ID
        Long userId = StpUtil.getLoginIdAsLong();

        // 根据ID查找用户
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 更新用户信息
        if (request.getNickname() != null) {
            user.setNickname(request.getNickname());
        }
        if (request.getAvatar() != null) {
            user.setAvatar(request.getAvatar());
        }
        if (request.getGender() != null) {
            user.setGender(request.getGender());
        }
        if (request.getEmail() != null) {
            user.setEmail(request.getEmail());
        }
        if (request.getPhone() != null) {
            user.setPhone(request.getPhone());
        }
        if (request.getIntroduction() != null) {
            user.setIntroduction(request.getIntroduction());
        }

        // 保存用户
        user = userRepository.save(user);

        // 返回用户DTO
        return convertToDTO(user);
    }

    @Override
    @Transactional
    public boolean updatePassword(PasswordUpdateRequest request) {
        // 获取当前登录用户ID
        Long userId = StpUtil.getLoginIdAsLong();

        // 根据ID查找用户
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 检查旧密码
        if (!BCrypt.checkpw(request.getOldPassword(), user.getPassword())) {
            throw new RuntimeException("旧密码错误");
        }

        // 检查两次密码是否一致
        if (!request.getNewPassword().equals(request.getConfirmPassword())) {
            throw new RuntimeException("两次密码不一致");
        }

        // 更新密码
        user.setPassword(BCrypt.hashpw(request.getNewPassword()));

        // 保存用户
        userRepository.save(user);

        return true;
    }

    @Override
    public UserDTO getUserStats(Long userId) {
        // 根据ID查找用户
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 转换为DTO
        UserDTO userDTO = convertToDTO(user);

        // 获取统计数据
        userDTO.setCollectMusicCount(userCollectMusicRepository.countByUser(user));
        userDTO.setCollectPlaylistCount(userCollectPlaylistRepository.countByUser(user));
        userDTO.setCollectSingerCount(userCollectSingerRepository.countByUser(user));
        userDTO.setCreatePlaylistCount(playlistRepository.countByCreator(user));

        return userDTO;
    }

    @Override
    public PageResult<UserDTO> getUserList(Integer page, Integer size, String keyword) {
        // 创建分页对象
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime"));

        // 创建查询条件
        Specification<User> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            // 关键字查询
            if (keyword != null && !keyword.isEmpty()) {
                predicates.add(criteriaBuilder.or(
                        criteriaBuilder.like(root.get("username"), "%" + keyword + "%"),
                        criteriaBuilder.like(root.get("nickname"), "%" + keyword + "%"),
                        criteriaBuilder.like(root.get("email"), "%" + keyword + "%")
                ));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };

        // 查询
        Page<User> userPage = userRepository.findAll(specification, pageable);

        // 转换为DTO
        List<UserDTO> userDTOList = userPage.getContent().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        // 返回分页结果
        return new PageResult<>(userDTOList, userPage.getTotalElements(), page, size);
    }

    @Override
    @Transactional
    public boolean deleteUser(Long id) {
        // 检查用户是否存在
        if (!userRepository.existsById(id)) {
            throw new RuntimeException("用户不存在");
        }

        // 删除用户
        userRepository.deleteById(id);

        return true;
    }

    @Override
    @Transactional
    public boolean updateUserStatus(Long id, Integer status) {
        // 根据ID查找用户
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 更新状态
        user.setStatus(status);

        // 保存用户
        userRepository.save(user);

        return true;
    }

    @Override
    public UserDTO adminUpdateUser(Long id, UserUpdateRequest request) {
        User user = getById(id);

        // 更新用户信息
        if (request.getNickname() != null) {
            user.setNickname(request.getNickname());
        }
        if (request.getAvatar() != null) {
            user.setAvatar(request.getAvatar());
        }
        if (request.getGender() != null) {
            user.setGender(request.getGender());
        }
        if (request.getEmail() != null) {
            user.setEmail(request.getEmail());
        }
        if (request.getPhone() != null) {
            user.setPhone(request.getPhone());
        }
        if (request.getIntroduction() != null) {
            user.setIntroduction(request.getIntroduction());
        }

        // 保存用户
        User savedUser = userRepository.save(user);

        return convertToDTO(savedUser);
    }

    @Override
    public User getById(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }

    /**
     * 将用户实体转换为DTO
     *
     * @param user 用户实体
     * @return 用户DTO
     */
    private UserDTO convertToDTO(User user) {
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);
        
        // 确保头像URL是完整路径
        if (userDTO.getAvatar() != null && !userDTO.getAvatar().startsWith("http")) {
            userDTO.setAvatar("http://localhost:8085" + userDTO.getAvatar());
        }
        
        return userDTO;
    }
}
