package com.yupi.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.project.common.ErrorCode;
import com.yupi.project.constant.UserConstant;
import com.yupi.project.exception.BusinessException;
import com.yupi.project.mapper.UserMapper;
import com.yupi.project.model.entity.User;
import com.yupi.project.service.UserService;
import com.yupi.project.service.ChargingSessionService;
import com.yupi.project.model.entity.ChargingSession;
import com.yupi.project.model.enums.ChargingSessionStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * 用户服务实现类
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private ChargingSessionService chargingSessionService;

    // 用户名校验正则：允许字母、数字、下划线，长度4到16位
    private static final String USERNAME_PATTERN = "^[a-zA-Z0-9_]{4,16}$";
    // 密码校验正则：至少包含字母和数字，长度至少6位
    private static final String PASSWORD_PATTERN = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{6,}$";

    @Override
    public long userRegister(String username, String password, String checkPassword) {
        // 1. 参数校验
        if (StringUtils.isAnyBlank(username, password, checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        if (!Pattern.matches(USERNAME_PATTERN, username)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名不符合规范（4-16位字母、数字、下划线）");
        }
        if (password.length() < 6) { // 使用更宽松的校验，正则校验留给前端
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码长度不能小于6位");
        }
        if (!password.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
        }

        synchronized (username.intern()) {
            // 2. 检查用户名是否已存在
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("username", username);
            long count = this.count(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名已存在");
            }

            // 3. 密码加密
            String encodedPassword = passwordEncoder.encode(password);

            // 4. 创建用户
            User userToSave = new User();
            userToSave.setUsername(username);
            userToSave.setPassword(encodedPassword);
            userToSave.setRole(UserConstant.DEFAULT_ROLE); // 默认角色 'user'
            userToSave.setBalance(BigDecimal.ZERO); // 初始余额为0
            boolean saveResult = this.save(userToSave);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");
            }
            return userToSave.getId();
        }
    }

    @Override
    public User userLogin(String username, String password, HttpServletRequest request) {
        // 1. 参数校验
        if (StringUtils.isAnyBlank(username, password)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名或密码不能为空");
        }
        if (!Pattern.matches(USERNAME_PATTERN, username)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名格式错误");
        }

        // 2. 查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = this.getOne(queryWrapper);
        
        // 3. 校验密码 和 用户存在性
        if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名或密码错误");
        }

        // 4. 用户脱敏
        User safetyUser = getSafetyUser(user);

        // 5. 创建 Authentication 对象并设置到 SecurityContext
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        if (StringUtils.isNotBlank(user.getRole())) { // 确保角色不为空
            authorities.add(new SimpleGrantedAuthority(user.getRole()));
        }
        
        Authentication authentication = new UsernamePasswordAuthenticationToken(safetyUser, null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        return safetyUser;
    }

    @Override
    public User getCurrentUser(HttpServletRequest request) {
        // 优先从 SecurityContextHolder 获取认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated() && !(authentication.getPrincipal() instanceof String && "anonymousUser".equals(authentication.getPrincipal()))) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof User) {
                User userFromContext = (User) principal;
                // 根据 Context 中的用户ID，从数据库重新获取最新的用户信息
                User latestUser = this.getById(userFromContext.getId());
                if (latestUser != null && latestUser.getIsDeleted() == 0) { // 确保用户未被删除
                    // 返回脱敏后的最新用户信息
                    return getSafetyUser(latestUser);
                } else {
                    // 如果根据ID查不到用户了（例如被删除了），则认为未登录或异常
                    // 清除可能无效的认证信息
                    SecurityContextHolder.clearContext();
                    throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户状态异常或已失效，请重新登录");
                }
            } else if (principal instanceof org.springframework.security.core.userdetails.User) {
                // 如果是Spring Security的User对象，通常包含username
                org.springframework.security.core.userdetails.User springUser = (org.springframework.security.core.userdetails.User) principal;
                User userByUsername = this.getOne(new QueryWrapper<User>().eq("username", springUser.getUsername()));
                if (userByUsername != null && userByUsername.getIsDeleted() == 0) {
                    return getSafetyUser(userByUsername);
                } else {
                    SecurityContextHolder.clearContext();
                    throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户状态异常或已失效，请重新登录");
                }
            }
        }

        // 如果 SecurityContextHolder 中没有有效信息，尝试从 session (旧逻辑，可作为后备)
        // 注意：如果完全依赖 Spring Security，这部分可以考虑移除或调整
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if (userObj instanceof User) {
            User userFromSession = (User) userObj;
            User latestUser = this.getById(userFromSession.getId());
            if (latestUser != null && latestUser.getIsDeleted() == 0) {
                // 如果session中的用户有效，也最好将其信息同步到SecurityContext以保持一致性 (可选)
                // recreateAuthenticationInSecurityContext(latestUser, request); // 辅助方法，如果需要
                return getSafetyUser(latestUser);
            }
            // Session 中的用户信息无效
            request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "会话已过期或无效，请重新登录");
        }

        throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
    }

    @Override
    public boolean userLogout(HttpServletRequest request) {
        SecurityContextHolder.clearContext(); // 清除安全上下文
        if (request.getSession(false) != null) { // 获取session但不创建新的
            request.getSession(false).invalidate(); // 使session无效
        }
        return true;
    }

    @Override
    public User getSafetyUser(User originUser) {
        if (originUser == null) {
            return null;
        }
        User safetyUser = new User();
        BeanUtils.copyProperties(originUser, safetyUser, "password");
        return safetyUser;
    }

    @Override
    public List<User> listUsers() {
        List<User> userList = this.list(new QueryWrapper<User>().eq("isDeleted", 0));
        return userList.stream().map(this::getSafetyUser).collect(Collectors.toList());
    }

    // 新增管理员删除用户实现
    @Override
    public boolean adminDeleteUser(Long userId) {
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID参数错误");
        }
        User user = this.getById(userId);
        if (user == null || user.getIsDeleted() == 1) { 
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在或已被删除");
        }
        boolean result = this.removeById(userId);
        if (!result) {
            log.warn("Attempted to delete user that might already be deleted or does not exist, userId: {}", userId);
            User checkUser = this.getById(userId);
            if(checkUser == null || checkUser.getIsDeleted() == 1){
                 return true; 
            }
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除用户失败，数据库操作异常");
        }
        log.info("User with id: {} logically deleted by admin.", userId);
        return true;
    }

    // 新增管理员添加用户实现
    @Override
    @Transactional // 确保操作的原子性
    public long adminAddUser(com.yupi.project.model.dto.user.UserAdminAddRequest addRequest) {
        String username = addRequest.getUsername();
        String password = addRequest.getPassword();
        String role = addRequest.getRole();
        BigDecimal balance = addRequest.getBalance();

        // 1. 参数校验
        if (StringUtils.isAnyBlank(username, password, role)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名、密码和角色不能为空");
        }
        if (!Pattern.matches(USERNAME_PATTERN, username)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名不符合规范（4-16位字母、数字、下划线）");
        }
        if (password.length() < 6) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码长度不能小于6位");
        }
        // 校验角色是否合法 (例如：必须是 UserRoleEnum 中的值)
        try {
            com.yupi.project.model.enums.UserRoleEnum.valueOf(role.toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无效的用户角色");
        }
        if (balance != null && balance.compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "初始余额不能为负数");
        }

        synchronized (username.intern()) {
            // 2. 检查用户名是否已存在
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("username", username);
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名已存在");
            }

            // 3. 密码加密
            String encodedPassword = passwordEncoder.encode(password);

            // 4. 创建用户
            User newUser = new User();
            newUser.setUsername(username);
            newUser.setPassword(encodedPassword);
            newUser.setRole(role); // 直接使用管理员指定的角色
            newUser.setBalance(balance != null ? balance : BigDecimal.ZERO); // 如果未提供余额，默认为0
            
            boolean saveResult = this.save(newUser);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "添加用户失败，数据库错误");
            }
            log.info("Admin added new user: {}, ID: {}, Role: {}", username, newUser.getId(), role);
            return newUser.getId();
        }
    }

    // 新增管理员更新用户实现
    @Override
    @Transactional
    public boolean adminUpdateUser(com.yupi.project.model.dto.user.UserAdminUpdateRequest updateRequest) {
        Long userId = updateRequest.getId();
        if (userId == null || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID不能为空");
        }

        User existingUser = this.getById(userId);
        if (existingUser == null || existingUser.getIsDeleted() == 1) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在或已被删除");
        }

        boolean needsUpdate = false;
        User userToUpdate = new User();
        userToUpdate.setId(userId);

        // 更新用户名 (如果提供)
        if (StringUtils.isNotBlank(updateRequest.getUsername())) {
            String newUsername = updateRequest.getUsername();
            if (!Pattern.matches(USERNAME_PATTERN, newUsername)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "新用户名不符合规范");
            }
            // 检查新用户名是否与现有其他用户冲突
            if (!existingUser.getUsername().equals(newUsername)) {
                QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("username", newUsername).ne("id", userId);
                if (this.count(queryWrapper) > 0) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "新用户名已被其他用户使用");
                }
                userToUpdate.setUsername(newUsername);
                needsUpdate = true;
            }
        }

        // 更新密码 (如果提供)
        if (StringUtils.isNotBlank(updateRequest.getPassword())) {
            String newPassword = updateRequest.getPassword();
            if (newPassword.length() < 6) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "新密码长度不能小于6位");
            }
            userToUpdate.setPassword(passwordEncoder.encode(newPassword));
            needsUpdate = true;
        }

        // 更新角色 (如果提供)
        if (StringUtils.isNotBlank(updateRequest.getRole())) {
            String newRole = updateRequest.getRole();
            try {
                com.yupi.project.model.enums.UserRoleEnum.valueOf(newRole.toUpperCase());
            } catch (IllegalArgumentException e) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "无效的新用户角色");
            }
            userToUpdate.setRole(newRole);
            needsUpdate = true;
        }

        // 更新余额 (如果提供)
        if (updateRequest.getBalance() != null) {
            BigDecimal newBalance = updateRequest.getBalance();
            if (newBalance.compareTo(BigDecimal.ZERO) < 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "余额不能为负数");
            }
            userToUpdate.setBalance(newBalance);
            needsUpdate = true;
        }

        if (!needsUpdate) {
            log.info("No fields to update for user ID: {}", userId);
            return true; // 没有字段需要更新，也视为成功
        }

        boolean updateResult = this.updateById(userToUpdate);
        if (!updateResult) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新用户信息失败，数据库操作异常");
        }
        log.info("User ID: {} updated by admin. Fields updated: username={}, role={}, balance={}, password_changed={}", 
            userId, 
            userToUpdate.getUsername() != null,
            userToUpdate.getRole() != null,
            userToUpdate.getBalance() != null,
            userToUpdate.getPassword() != null
        );
        return true;
    }

    @Override
    @Transactional
    public boolean decreaseBalance(Long userId, BigDecimal amountToDecrease) {
        if (userId == null || amountToDecrease == null || amountToDecrease.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID或扣款金额无效");
        }

        User user = this.getById(userId);
        if (user == null) {
            // 即使SQL会因为用户不存在而不更新，这里提前检查可以提供更明确的错误信息
            log.warn("尝试为不存在的用户ID {} 扣款 {} 失败。", userId, amountToDecrease);
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在，无法扣款");
        }

        // 数据库层面的原子操作将处理余额是否足够
        // The amountChange passed to mapper is negative for decrease
        int updatedRows = baseMapper.updateUserBalance(userId, amountToDecrease.negate());

        if (updatedRows > 0) {
            log.info("用户 {} 余额扣款 {} 成功 (通过原子操作)。", userId, amountToDecrease);
            // 获取更新后的余额用于日志记录是可选的，且可能引入额外查询。为简单起见，此处省略。
            return true;
        } else {
            // updatedRows == 0 表示扣款未成功，主要原因是余额不足（由SQL的WHERE子句保证）或用户ID无效（可能性较低，因已预查）
            log.warn("用户 {} 余额扣款 {} 失败。原子操作更新行数为0，通常表示余额不足或用户不存在。", userId, amountToDecrease);
            // 可以选择再次查询用户以确认具体原因，但对于调用方来说，false已足够
            return false;
        }
    }

    @Override
    @Transactional
    public boolean increaseBalance(Long userId, BigDecimal amountToIncrease) {
        if (userId == null || amountToIncrease == null || amountToIncrease.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID或增加金额无效");
        }

        // Ensure user exists before attempting to update
        User user = this.getById(userId);
        if (user == null) {
            log.warn("尝试为不存在的用户 {} 增加余额 {} 失败。", userId, amountToIncrease);
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在，无法增加余额");
        }

        int updatedRows = baseMapper.updateUserBalance(userId, amountToIncrease);

        if (updatedRows > 0) {
            log.info("用户 {} 余额增加 {} 成功。当前余额: {}", userId, amountToIncrease, user.getBalance().add(amountToIncrease));
            return true;
        } else {
            // This case should ideally not happen if user existence is checked before, unless user is deleted concurrently.
            log.warn("用户 {} 余额增加 {} 失败，更新数据库记录数为0。", userId, amountToIncrease);
            return false;
        }
    }

    @Override
    public Map<String, Object> getUserDashboardStats(Long userId) {
        if (userId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID不能为空");
        }

        // 获取本月的第一天和最后一天
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0);
        LocalDateTime lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59);

        Date startDate = Date.from(firstDayOfMonth.atZone(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(lastDayOfMonth.atZone(ZoneId.systemDefault()).toInstant());

        // 查询本月已完成的充电会话
        QueryWrapper<ChargingSession> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("status", ChargingSessionStatusEnum.PAID.getValue()); // 修正: COMPLETED -> PAID (统计已支付完成的会话)
        queryWrapper.between("charge_end_time", startDate, endDate); // 假设用 charge_end_time 判断是否在本月完成

        List<ChargingSession> monthlySessions = chargingSessionService.list(queryWrapper);

        long monthlyCharges = monthlySessions.size();
        BigDecimal monthlySpending = BigDecimal.ZERO;

        for (ChargingSession session : monthlySessions) {
            if (session.getCost() != null) {
                monthlySpending = monthlySpending.add(session.getCost());
            }
        }

        Map<String, Object> stats = new HashMap<>();
        stats.put("monthlyCharges", monthlyCharges);
        stats.put("monthlySpending", monthlySpending.setScale(2, BigDecimal.ROUND_HALF_UP));

        return stats;
    }
}