package com.example.demo.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.model.PointsFreezeRecord;
import com.example.demo.model.User;
import com.example.demo.repository.PointsFreezeRecordRepository;
import com.example.demo.repository.UserRepository;

@Service
public class UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserService.class);

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final PointsFreezeRecordRepository pointsFreezeRecordRepository;

    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, PointsFreezeRecordRepository pointsFreezeRecordRepository) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.pointsFreezeRecordRepository = pointsFreezeRecordRepository;
    }

    @Transactional
    public User register(String username, String email, String rawPassword) {
        if (userRepository.existsByUsername(username)) {
            throw new IllegalArgumentException("用户名已存在");
        }
        if (userRepository.existsByEmail(email)) {
            throw new IllegalArgumentException("邮箱已被使用");
        }
        User user = new User();
        user.setUsername(username);
        user.setEmail(email);
        user.setPasswordHash(passwordEncoder.encode(rawPassword));
        // 注册时默认为普通用户
        user.setRole("ROLE_USER");
        return userRepository.save(user);
    }

    @Transactional(readOnly = true)
    public java.util.List<User> findAll() {
        return userRepository.findAll();
    }

    @Transactional(readOnly = true)
    public User findById(Long id) {
        return userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("用户不存在"));
    }

    @Transactional(readOnly = true)
    public User findByUsername(String username) {
        return userRepository.findByUsername(username).orElseThrow(() -> new IllegalArgumentException("用户不存在"));
    }

    @Transactional(readOnly = true)
    public User findByUsernameOrNull(String username) {
        return userRepository.findByUsername(username).orElse(null);
    }

    @Transactional
    public User create(String username, String email, String rawPassword) {
        return register(username, email, rawPassword);
    }

    @Transactional
    public User update(Long id, String username, String email, String rawPasswordNullable) {
        return update(id, username, email, rawPasswordNullable, null);
    }

    @Transactional
    public User update(Long id, String username, String email, String rawPasswordNullable, String role) {
        User user = findById(id);
        if (!user.getUsername().equals(username) && userRepository.existsByUsername(username)) {
            throw new IllegalArgumentException("用户名已存在");
        }
        if (!user.getEmail().equals(email) && userRepository.existsByEmail(email)) {
            throw new IllegalArgumentException("邮箱已被使用");
        }
        user.setUsername(username);
        user.setEmail(email);
        if (role != null && !role.isBlank()) {
            user.setRole(role);
        }
        if (rawPasswordNullable != null && !rawPasswordNullable.isBlank()) {
            user.setPasswordHash(rawPasswordNullable);
        }
        return userRepository.save(user);
    }

    @Transactional
    public void delete(Long id) {
        userRepository.deleteById(id);
    }

    /**
     * 检查密码是否匹配（加密比较）
     */
    public boolean checkPassword(String rawPassword, String storedPassword) {
        return passwordEncoder.matches(rawPassword, storedPassword);
    }

    /**
     * 根据邮箱查找用户
     */
    @Transactional(readOnly = true)
    public User findByEmail(String email) {
        return userRepository.findByEmail(email).orElse(null);
    }

    /**
     * 根据手机号查找用户
     */
    @Transactional(readOnly = true)
    public User findByPhone(String phone) {
        return userRepository.findByPhone(phone).orElse(null);
    }

    /**
     * 保存用户
     */
    @Transactional
    public User save(User user) {
        return userRepository.save(user);
    }

    /**
     * 增加用户积分
     */
    @Transactional
    public User addPoints(Long userId, Integer points) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        int newPoints = user.getPoints() + points;
        if (newPoints < 0) {
            throw new RuntimeException("积分不能为负数");
        }
        
        user.setPoints(newPoints);
        return userRepository.save(user);
    }

    /**
     * 减少用户积分
     */
    @Transactional
    public User deductPoints(Long userId, Integer points) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        int newPoints = user.getPoints() - points;
        if (newPoints < 0) {
            throw new RuntimeException("积分不足");
        }
        
        user.setPoints(newPoints);
        return userRepository.save(user);
    }

    /**
     * 冻结用户积分
     */
    @Transactional
    public PointsFreezeRecord freezePoints(String username, String taskId, PointsFreezeRecord.TaskType taskType, Integer points, String reason) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // 检查可用积分是否足够
        if (user.getAvailablePoints() < points) {
            throw new RuntimeException("可用积分不足，当前可用积分: " + user.getAvailablePoints() + "，需要积分: " + points);
        }
        
        // 检查总积分是否足够（防止冻结积分过多导致总积分为负）
        if (user.getPoints() < points) {
            throw new RuntimeException("总积分不足，当前总积分: " + user.getPoints() + "，需要积分: " + points);
        }
        
        // 增加冻结积分
        user.setFrozenPoints(user.getFrozenPoints() + points);
        userRepository.save(user);
        
        // 创建冻结记录
        PointsFreezeRecord record = new PointsFreezeRecord(username, taskId, taskType, points, reason);
        record = pointsFreezeRecordRepository.save(record);
        
        logger.info("用户 {} 冻结积分成功: {} 积分，任务ID: {}", username, points, taskId);
        return record;
    }

    /**
     * 扣除冻结的积分（任务完成）
     */
    @Transactional
    public void deductFrozenPoints(String taskId) {
        PointsFreezeRecord record = pointsFreezeRecordRepository.findByTaskId(taskId)
            .orElseThrow(() -> new RuntimeException("找不到冻结记录: " + taskId));
        
        if (record.getStatus() != PointsFreezeRecord.FreezeStatus.FROZEN) {
            throw new RuntimeException("冻结记录状态不正确: " + record.getStatus());
        }
        
        User user = userRepository.findByUsername(record.getUsername())
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // 减少总积分和冻结积分
        user.setPoints(user.getPoints() - record.getFreezePoints());
        user.setFrozenPoints(user.getFrozenPoints() - record.getFreezePoints());
        userRepository.save(user);
        
        // 更新冻结记录状态
        record.updateStatus(PointsFreezeRecord.FreezeStatus.DEDUCTED);
        pointsFreezeRecordRepository.save(record);
        
        logger.info("用户 {} 扣除冻结积分成功: {} 积分，任务ID: {}", record.getUsername(), record.getFreezePoints(), taskId);
    }

    /**
     * 返还冻结的积分（任务失败）
     */
    @Transactional
    public void returnFrozenPoints(String taskId) {
        PointsFreezeRecord record = pointsFreezeRecordRepository.findByTaskId(taskId)
            .orElseThrow(() -> new RuntimeException("找不到冻结记录: " + taskId));
        
        if (record.getStatus() != PointsFreezeRecord.FreezeStatus.FROZEN) {
            throw new RuntimeException("冻结记录状态不正确: " + record.getStatus());
        }
        
        User user = userRepository.findByUsername(record.getUsername())
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // 减少冻结积分（总积分不变）
        user.setFrozenPoints(user.getFrozenPoints() - record.getFreezePoints());
        userRepository.save(user);
        
        // 更新冻结记录状态
        record.updateStatus(PointsFreezeRecord.FreezeStatus.RETURNED);
        pointsFreezeRecordRepository.save(record);
        
        logger.info("用户 {} 返还冻结积分成功: {} 积分，任务ID: {}", record.getUsername(), record.getFreezePoints(), taskId);
    }

    /**
     * 给用户增加积分
     */
    @Transactional
    public void addPoints(String username, Integer points) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在: " + username));
        
        user.setPoints(user.getPoints() + points);
        userRepository.save(user);
        
        logger.info("用户 {} 积分增加: {} 积分，当前积分: {}", username, points, user.getPoints());
    }

    /**
     * 设置用户积分
     */
    @Transactional
    public void setPoints(String username, Integer points) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在: " + username));
        
        user.setPoints(points);
        userRepository.save(user);
        
        logger.info("用户 {} 积分设置为: {} 积分", username, points);
    }

    /**
     * 获取用户可用积分
     */
    @Transactional(readOnly = true)
    public Integer getAvailablePoints(String username) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        return user.getAvailablePoints();
    }

    /**
     * 获取用户冻结积分
     */
    @Transactional(readOnly = true)
    public Integer getFrozenPoints(String username) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        return user.getFrozenPoints();
    }

    /**
     * 获取用户积分冻结记录
     */
    @Transactional(readOnly = true)
    public java.util.List<PointsFreezeRecord> getPointsFreezeRecords(String username) {
        return pointsFreezeRecordRepository.findByUsernameOrderByCreatedAtDesc(username);
    }

    /**
     * 处理过期的冻结记录
     */
    @Transactional
    public int processExpiredFrozenRecords() {
        java.time.LocalDateTime expiredTime = java.time.LocalDateTime.now().minusHours(24);
        java.util.List<PointsFreezeRecord> expiredRecords = pointsFreezeRecordRepository.findExpiredFrozenRecords(expiredTime);
        
        int processedCount = 0;
        for (PointsFreezeRecord record : expiredRecords) {
            try {
                // 返还过期冻结的积分
                returnFrozenPoints(record.getTaskId());
                processedCount++;
                logger.info("处理过期冻结记录: {}", record.getTaskId());
            } catch (Exception e) {
                logger.error("处理过期冻结记录失败: {}", record.getTaskId(), e);
            }
        }
        
        return processedCount;
    }

    /**
     * 获取用户积分
     */
    @Transactional(readOnly = true)
    public Integer getUserPoints(Long userId) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        return user.getPoints();
    }
}
