package com.haha.admin.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.haha.admin.service.AdminLoginService;
import com.haha.common.enums.CommonStatus;
import com.haha.common.vo.AdminInfoVO;
import com.haha.common.vo.LoginVO;
import com.haha.common.vo.Result;
import com.haha.common.vo.UserVO;
import com.haha.entity.Admin;
import com.haha.entity.Role;
import com.haha.mapper.AdminMapper;
import com.haha.mapper.RoleMapper;
import com.haha.service.DataPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 管理员登录服务实现
 */
@Slf4j
@Service
public class AdminLoginServiceImpl implements AdminLoginService {
    
    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private DataPermissionService dataPermissionService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final String REFRESH_TOKEN_PREFIX = "refreshToken:admin:";
    private static final Duration REFRESH_TOKEN_TTL = Duration.ofDays(7);
    private static final int TOKEN_TIMEOUT_SECONDS = 28800;
    
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    
    @Override
    public Result<LoginVO> login(String username, String password) {
        try {
            log.info("管理员登录尝试: username={}", username);
            
            // 参数校验
            if (username == null || username.trim().isEmpty()) {
                return Result.error(400, "用户名不能为空");
            }
            if (password == null || password.trim().isEmpty()) {
                return Result.error(400, "密码不能为空");
            }
            
            // ====== 临时方案：硬编码测试账号（仅用于开发测试，生产环境必须移除） ======
            if ("admin".equals(username) && "admin123".equals(password)) {
                log.warn("【临时测试账号登录】username={} - 此逻辑仅用于开发测试，生产环境必须移除", username);
                
                // 创建临时管理员对象
                Admin admin = new Admin();
                admin.setId(999L);
                admin.setUsername("admin");
                admin.setRealName("临时测试管理员");
                admin.setPhone("13800138000");
                admin.setEmail("admin@haha.com");
                admin.setAvatar(null);
                admin.setDepartment("技术部");
                admin.setStatus(CommonStatus.ENABLED.getCode());
                admin.setRoleIds("1");
                
                // 使用Sa-Token进行登录,生成token
                StpUtil.login(admin.getId());

                // 在Session中存储用户信息
                StpUtil.getSession().set("username", admin.getUsername());
                StpUtil.getSession().set("realName", admin.getRealName());
                StpUtil.getSession().set("roleIds", admin.getRoleIds());

                // 获取并存储用户权限列表
                List<String> permissions = getUserPermissions("1");
                StpUtil.getSession().set("permissions", permissions);

                log.info("【临时测试账号】登录成功: username={}, userId={}", username, admin.getId());

                return Result.success("登录成功", buildLoginResult(admin, permissions, List.of("admin")));
            }
            // ====== 以上为临时测试逻辑，生产环境必须移除 ======
            
            // 查询管理员信息
            LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Admin::getUsername, username);
            Admin admin = adminMapper.selectOne(wrapper);
            
            if (admin == null) {
                log.warn("登录失败: 用户名不存在 username={}", username);
                return Result.error(401, "用户名或密码错误");
            }
            
            // 检查账号状态
            if (!CommonStatus.isEnabled(admin.getStatus())) {
                log.warn("登录失败: 账号已禁用 username={}", username);
                return Result.error(403, "账号已被禁用，请联系管理员");
            }
            
            // 验证密码
            if (!passwordEncoder.matches(password, admin.getPassword())) {
                log.warn("登录失败: 密码错误 username={}", username);
                return Result.error(401, "用户名或密码错误");
            }
            
            // 更新最后登录时间和IP(这里简化处理，实际应从HttpServletRequest获取IP)
            admin.setLastLoginTime(LocalDateTime.now());
            admin.setLastLoginIp("127.0.0.1");
            adminMapper.updateById(admin);
            
            // 使用Sa-Token进行登录,生成token
            StpUtil.login(admin.getId());

            // 在Session中存储用户信息
            StpUtil.getSession().set("username", admin.getUsername());
            StpUtil.getSession().set("realName", admin.getRealName());
            StpUtil.getSession().set("roleIds", admin.getRoleIds());
            
            // 获取并存储用户权限列表
            List<String> permissions = getUserPermissions(admin.getRoleIds());
            StpUtil.getSession().set("permissions", permissions);
            
            // 获取用户的角色编码列表
            List<String> roleCodes = getRoleCodes(admin.getRoleIds());
            
            log.info("管理员登录成功: username={}, userId={}", username, admin.getId());

            return Result.success("登录成功", buildLoginResult(admin, permissions, roleCodes));
            
        } catch (Exception e) {
            log.error("登录异常: username={}, error={}", username, e.getMessage(), e);
            return Result.error(500, "登录失败: " + e.getMessage());
        }
    }
    
    @Override
    public Result<AdminInfoVO> getAdminInfo(String adminId) {
        try {
            // 查询管理员信息
            Admin admin = adminMapper.selectById(adminId);
            if (admin == null) {
                return Result.error(404, "管理员不存在");
            }
            
            // 获取用户权限列表
            List<String> permissions = getUserPermissions(admin.getRoleIds());
            
            AdminInfoVO info = AdminInfoVO.builder()
                    .id(admin.getId())
                    .username(admin.getUsername())
                    .realName(admin.getRealName())
                    .phone(admin.getPhone())
                    .email(admin.getEmail())
                    .avatar(admin.getAvatar())
                    .department(admin.getDepartment())
                    .roleIds(admin.getRoleIds())
                    .permissions(permissions)
                    .build();
            
            return Result.success("获取成功", info);
            
        } catch (Exception e) {
            log.error("获取管理员信息异常: adminId={}, error={}", adminId, e.getMessage(), e);
            return Result.error(500, "获取信息失败: " + e.getMessage());
        }
    }

    /**
     * 根据角色ID列表获取用户权限
     * @param roleIdsStr 角色ID字符串(逗号分隔)
     * @return 权限编码列表
     */
    private List<String> getUserPermissions(String roleIdsStr) {
        if (roleIdsStr == null || roleIdsStr.trim().isEmpty()) {
            return List.of();
        }
        
        try {
            List<Long> roleIds = Arrays.stream(roleIdsStr.split(","))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
            
            return dataPermissionService.getPermissionCodesByRoleIds(roleIds);
        } catch (Exception e) {
            log.error("获取用户权限失败: roleIds={}, error={}", roleIdsStr, e.getMessage());
            return List.of();
        }
    }

    /**
     * 根据角色ID列表获取角色编码
     * @param roleIdsStr 角色ID字符串(逗号分隔)
     * @return 角色编码列表
     */
    private List<String> getRoleCodes(String roleIdsStr) {
        if (roleIdsStr == null || roleIdsStr.trim().isEmpty()) {
            return List.of();
        }

        try {
            List<Long> roleIds = Arrays.stream(roleIdsStr.split(","))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .map(Long::parseLong)
                    .collect(Collectors.toList());

            if (roleIds.isEmpty()) {
                return List.of();
            }

            return roleMapper.selectByIds(roleIds)
                    .stream()
                    .map(Role::getCode)
                    .filter(code -> code != null && !code.isEmpty())
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取角色编码失败: roleIds={}, error={}", roleIdsStr, e.getMessage());
            return List.of();
        }
    }

    /**
     * 构建登录返回结果（含 refreshToken）
     */
    private LoginVO buildLoginResult(Admin admin, List<String> permissions, List<String> roles) {
        String token = StpUtil.getTokenValue();
        String refreshToken = UUID.randomUUID().toString();

        // 将 refreshToken 存入 Redis，关联 userId
        stringRedisTemplate.opsForValue().set(
                REFRESH_TOKEN_PREFIX + refreshToken,
                admin.getId().toString(),
                REFRESH_TOKEN_TTL
        );

        UserVO userVO = UserVO.builder()
                .id(admin.getId())
                .nickname(admin.getRealName() != null ? admin.getRealName() : admin.getUsername())
                .avatar(admin.getAvatar())
                .phone(admin.getPhone())
                .roles(roles)
                .permissions(permissions)
                .build();

        return LoginVO.builder()
                .token(token)
                .refreshToken(refreshToken)
                .tokenTimeout(TOKEN_TIMEOUT_SECONDS)
                .userInfo(userVO)
                .build();
    }

    @Override
    public Result<LoginVO> refreshToken(String refreshToken) {
        if (refreshToken == null || refreshToken.isBlank()) {
            return Result.error(400, "refreshToken 不能为空");
        }

        String key = REFRESH_TOKEN_PREFIX + refreshToken;
        String userId = stringRedisTemplate.opsForValue().get(key);

        if (userId == null) {
            return Result.error(401, "refreshToken 无效或已过期");
        }

        // 删除旧的 refreshToken
        stringRedisTemplate.delete(key);

        // 注销旧的 Sa-Token 会话（如果存在）
        try {
            StpUtil.logout(Long.parseLong(userId));
        } catch (Exception ignored) {
        }

        // 重新登录
        StpUtil.login(Long.parseLong(userId));

        // 从旧 Session 恢复用户信息
        // 旧 session 已被注销，需要重新查询
        Admin admin = adminMapper.selectById(userId);
        if (admin == null) {
            return Result.error(404, "管理员不存在或已被删除");
        }

        List<String> permissions = getUserPermissions(admin.getRoleIds());
        List<String> roles = getRoleCodes(admin.getRoleIds());

        StpUtil.getSession().set("username", admin.getUsername());
        StpUtil.getSession().set("realName", admin.getRealName());
        StpUtil.getSession().set("roleIds", admin.getRoleIds());
        StpUtil.getSession().set("permissions", permissions);

        return Result.success("token 刷新成功", buildLoginResult(admin, permissions, roles));
    }
}
