package shop.alien.gateway.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import shop.alien.entity.result.R;
import shop.alien.entity.store.LifeSys;
import shop.alien.entity.store.LifeSysMenu;
import shop.alien.entity.store.UserLoginInfo;
import shop.alien.entity.store.vo.SystemLoginVo;
import shop.alien.gateway.config.BaseRedisService;
import shop.alien.gateway.feign.StoreServiceFeign;
import shop.alien.gateway.mapper.LifeSysGatewayMapper;
import shop.alien.gateway.service.SystemService;
import shop.alien.util.common.JwtUtil;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 商家会员记录 服务实现类
 * </p>
 *
 * @author ssk
 * @since 2025-02-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SystemServiceImpl implements SystemService {

    private final LifeSysGatewayMapper lifeSysMapper;

    @Autowired
    private final StoreServiceFeign storeServiceFeign;

    private final BaseRedisService baseRedisService;

    @Value("${jwt.expiration-time}")
    private String effectiveTime;

    @Override
    public SystemLoginVo login(String username, String password) {
        int effectiveTimeInt = Integer.parseInt(effectiveTime.substring(0, effectiveTime.length() - 1));
        String effectiveTimeUnit = effectiveTime.substring(effectiveTime.length() - 1);
        long effectiveTimeIntLong = 0L;
        switch (effectiveTimeUnit) {
            case "s": {
                effectiveTimeIntLong = effectiveTimeInt * 1000L;
                break;
            }
            case "m": {
                effectiveTimeIntLong = effectiveTimeInt * 60L * 1000L;
                break;
            }
            case "h": {
                effectiveTimeIntLong = effectiveTimeInt * 60L * 60L * 1000L;
                break;
            }
            case "d": {
                effectiveTimeIntLong = effectiveTimeInt * 24L * 60L * 60L * 1000L;
                break;
            }
        }
        SystemLoginVo result = new SystemLoginVo();
        //给密码加密MD5，查询用户是否存在
        LifeSys lifeSys = lifeSysMapper.selectOne(
                new LambdaQueryWrapper<LifeSys>()
                        .eq(LifeSys::getUserName, username)
        );
        if (lifeSys != null && lifeSys.getUserPassword().equals(password)) {
            Map<String, String> tokenMap = new HashMap<>();
            tokenMap.put("phone", "123456");
            tokenMap.put("userName", lifeSys.getUserName());
            tokenMap.put("userId", String.valueOf(lifeSys.getId()));
            tokenMap.put("userType", "web");
            R<List<LifeSysMenu>> menuByUserId = storeServiceFeign.getMenuByUserId(lifeSys.getId().longValue(), 1L);
            List<LifeSysMenu> data = menuByUserId.getData();
            //存入token
            result.setToken(JwtUtil.createJWT("web_" + lifeSys.getId(), lifeSys.getUserName(), JSONObject.toJSONString(tokenMap), effectiveTimeIntLong));
            baseRedisService.setString("web_" + lifeSys.getUserName(), result.getToken());
            tokenMap.put("menuList", JSONObject.toJSONString(data));
            //登录结果
            result.setResult(true);
            //角色Id
            result.setRoleId(lifeSys.getRoleId());
            //菜单列表
            result.setMenuList(data);
            //登录结果
            result.setMessage("登录成功！！");
        } else {
            result.setResult(false);
            result.setMessage("用户名或者密码错误，请确认！！");
        }
        return result;
    }

    /**
     * 退出登录
     * <p>
     * 退出登录时会执行以下操作：
     * 1. 参数校验：验证用户登录信息是否有效
     * 2. 删除Redis中的token缓存（key格式：web_用户名）
     * 3. 返回退出登录结果
     * </p>
     *
     * @param userLoginInfo 用户登录信息，包含userId、userName等信息
     * @return SystemLoginVo 退出登录结果，包含退出状态信息
     * @throws IllegalArgumentException 当用户信息为空或用户名为空时抛出
     */
    @Override
    public SystemLoginVo logout(UserLoginInfo userLoginInfo) {
        // 参数校验
        if (userLoginInfo == null) {
            log.warn("退出登录失败：用户登录信息为空");
            throw new IllegalArgumentException("用户登录信息不能为空");
        }
        
        if (!StringUtils.hasText(userLoginInfo.getUserName())) {
            log.warn("退出登录失败：用户名为空，userId={}", userLoginInfo.getUserId());
            throw new IllegalArgumentException("用户名不能为空");
        }
        
        log.info("开始退出登录，userId={}, userName={}", userLoginInfo.getUserId(), userLoginInfo.getUserName());
        
        try {
            // 删除Redis中的token缓存
            String redisKey = "web_" + userLoginInfo.getUserName();
            String existingToken = baseRedisService.getString(redisKey);
            
            if (StringUtils.hasText(existingToken)) {
                baseRedisService.delete(redisKey);
                log.info("删除Redis token成功，redisKey={}, userId={}, userName={}", 
                        redisKey, userLoginInfo.getUserId(), userLoginInfo.getUserName());
            } else {
                log.warn("Redis中不存在token，可能已过期或已删除，redisKey={}, userId={}, userName={}", 
                        redisKey, userLoginInfo.getUserId(), userLoginInfo.getUserName());
            }
            
            // 构建返回结果
            SystemLoginVo result = new SystemLoginVo();
            result.setResult(true);
            result.setMessage("退出登录成功");
            
            log.info("退出登录成功，userId={}, userName={}", userLoginInfo.getUserId(), userLoginInfo.getUserName());
            return result;
        } catch (Exception e) {
            log.error("退出登录失败，userId={}, userName={}, error={}", 
                    userLoginInfo.getUserId(), userLoginInfo.getUserName(), e.getMessage(), e);
            throw new RuntimeException("退出登录失败：" + e.getMessage(), e);
        }
    }

    @Override
    public R<LifeSys> register(String userName, String password, String roleId, Integer status, String remark) {
        // 校验必填字段
        if (!StringUtils.hasText(userName)) {
            return R.fail("用户名不能为空");
        }
        if (!StringUtils.hasText(password)) {
            return R.fail("密码不能为空");
        }

        // 校验用户名是否已存在
        LambdaQueryWrapper<LifeSys> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LifeSys::getUserName, userName);
        LifeSys existingUser = lifeSysMapper.selectOne(queryWrapper);
        if (existingUser != null) {
            // 如果是 admin 用户，给出特殊提示
            if ("admin".equalsIgnoreCase(userName)) {
                return R.fail("admin 用户已存在，不允许重复添加");
            }
            return R.fail("该用户名已存在，请更换其他用户名");
        }

        // 额外校验：如果尝试注册 admin 用户，检查数据库中是否已存在 admin（防止大小写变体）
        if ("admin".equalsIgnoreCase(userName)) {
            LambdaQueryWrapper<LifeSys> adminQueryWrapper = new LambdaQueryWrapper<>();
            adminQueryWrapper.eq(LifeSys::getUserName, "admin");
            LifeSys adminUser = lifeSysMapper.selectOne(adminQueryWrapper);
            if (adminUser != null) {
                return R.fail("admin 用户已存在，不允许重复添加");
            }
        }

        // 创建新用户
        LifeSys lifeSys = new LifeSys();
        lifeSys.setUserName(userName);
        lifeSys.setUserPassword(password);
        lifeSys.setRoleId(roleId);
        lifeSys.setStatus(status);
        lifeSys.setDeleteFlag(0);
        lifeSys.setRemark(remark);
        lifeSys.setCreatedTime(new Date());

        // 密码使用MD5加密后存储
//        lifeSys.setUserPassword(encryptToMD5(password));
//        if (StringUtils.hasText(roleId)) {
//            lifeSys.setRoleId(roleId);
//        }

        // 保存用户
        int result = lifeSysMapper.insert(lifeSys);
        if (result > 0) {
            return R.data(lifeSys, "账号添加成功");
        }
        return R.fail("注册失败，请稍后重试");
    }

    @Override
    public int updateAccounInfo(LifeSys lifeSys) {
        return lifeSysMapper.updateById(lifeSys);
    }

    @Override
    public R<LifeSys> getById(Integer id) {
        if (id == null) {
            return R.fail("用户ID不能为空");
        }
        LifeSys lifeSys = lifeSysMapper.selectById(id);
        if (lifeSys == null) {
            return R.fail("用户不存在");
        }
        return R.data(lifeSys);
    }

    @Override
    public R<List<LifeSys>> list(String userName, Integer status) {
        LambdaQueryWrapper<LifeSys> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(userName)) {
            queryWrapper.like(LifeSys::getUserName, userName);
        }
        if (status != null) {
            queryWrapper.eq(LifeSys::getStatus, status);
        }
        queryWrapper.orderByDesc(LifeSys::getCreatedTime);
        List<LifeSys> list = lifeSysMapper.selectList(queryWrapper);
        
        // 如果用户名是 "admin"，则不返回 roleId
        for (LifeSys lifeSys : list) {
            if ("admin".equalsIgnoreCase(lifeSys.getUserName())) {
                lifeSys.setRoleId(null);
            }
        }
        
        return R.data(list);
    }

    @Override
    public R<String> deleteById(Integer id) {
        if (id == null) {
            return R.fail("用户ID不能为空");
        }
        // 先查询用户是否存在
        LifeSys lifeSys = lifeSysMapper.selectById(id);
        if (lifeSys == null) {
            return R.fail("用户不存在");
        }
        // 使用 MyBatis-Plus 的逻辑删除，会自动将 deleteFlag 设置为 1
        int result = lifeSysMapper.deleteById(id);
        if (result > 0) {
            return R.success("删除成功");
        }
        return R.fail("删除失败");
    }

    public static String encryptToMD5(String input) {
        try {
            // 获取 MD5 算法的 MessageDigest 实例
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 将输入的字符串转换为字节数组，并进行 MD5 计算
            byte[] messageDigest = md.digest(input.getBytes());

            // 创建一个 StringBuilder 用于存储十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest) {
                // 将字节转换为十六进制字符串
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) {
                    // 如果十六进制字符串长度为 1，则在前面补 0
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            // 返回最终的 MD5 加密后的十六进制字符串
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            // 若指定的算法（MD5）不可用，抛出运行时异常
            throw new RuntimeException(e);
        }
    }

}
