package org.xyzh.auth.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.xyzh.api.auth.login.LoginService;
import org.xyzh.auth.strategy.LoginStrategy;
import org.xyzh.auth.strategy.LoginStrategyFactory;
import org.xyzh.auth.util.JwtTokenUtil;
import org.xyzh.common.core.domain.LoginParam;
import org.xyzh.common.core.domain.LoginDomain;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.enums.UserStatus;
import org.xyzh.common.dto.permission.TbSysPermission;
import org.xyzh.common.dto.system.TbSysLoginLog;
import org.xyzh.common.dto.user.TbSysUser;
import org.xyzh.common.dto.menu.TbSysMenu;
import org.xyzh.common.exception.auth.AuthException;
import org.xyzh.common.utils.IDUtils;

import jakarta.servlet.http.HttpServletRequest;

import org.xyzh.api.system.user.UserService;
import org.xyzh.api.system.role.RoleService;
import org.xyzh.api.system.permission.PermissionService;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.api.system.menu.MenuService;
import org.xyzh.common.vo.DeptRoleVO;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;

/**
 * @description    LoginServiceImpl.java文件描述 登录服务实现
 * @filename    LoginServiceImpl.java
 * @author    yslg
 * @copyright xyzh
 * @since 2025-09-28
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private LoginStrategyFactory loginStrategyFactory;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private LoginLogService loginLogService;

    @Override
    public ResultDomain<LoginDomain> login(LoginParam loginParam, HttpServletRequest request) {
        ResultDomain<LoginDomain> result = new ResultDomain<>();
        String ipAddress = request.getRemoteAddr();
        try {
            // 自动检测登录类型
            String loginType = detectLoginType(loginParam);
            loginParam.setLoginType(loginType);

            // 获取对应的登录策略
            LoginStrategy strategy = loginStrategyFactory.getStrategy(loginType);

            // 验证登录参数
            if (!strategy.validate(loginParam)) {
                result.fail("登录参数不正确");
                return result;
            }

            // 查找用户
            TbSysUser user = strategy.findUser(loginParam);
            if (user == null) {
                result.fail("用户不存在");
                logLoginAttempt(loginParam, null, false, "用户不存在");
                return result;
            }

            // 检查用户状态
            UserStatus userStatus = UserStatus.fromCode(String.valueOf(user.getStatus()));
            if (userStatus != UserStatus.NORMAL) {
                result.fail("用户状态异常: " + userStatus.getName());
                logLoginAttempt(loginParam, user, false, "用户状态异常: " + userStatus.getName());
                return result;
            }

            if (loginType.equals("password")) {
                // 验证凭据（密码或验证码）
                if (!strategy.verifyCredential(loginParam.getPassword(), user.getPassword())) {
                    result.fail("密码错误");
                    logLoginAttempt(loginParam, user, false, "密码错误");
                    return result;
                }
            }
            else {
                // 验证凭据（验证码）
                String storedCaptcha = (String) redisService.get("captcha:" + loginParam.getPhone());
                if (!strategy.verifyCredential(loginParam.getCaptcha(), storedCaptcha)) {
                    result.fail("验证码错误");
                    logLoginAttempt(loginParam, user, false, "验证码错误");
                    return result;
                }
                // 验证码使用后删除
                redisService.delete("captcha:" + loginParam.getPhone());
            }

            // 构建登录域对象
            LoginDomain loginDomain = buildLoginDomain(user, loginType, ipAddress);
            // 生成JWT令牌
            loginDomain.setToken(jwtTokenUtil.generateToken(loginDomain));
            
            // 将LoginDomain存储到Redis中
            String redisKey = "login:token:" + user.getID();
            redisService.set(redisKey, loginDomain, 24 * 60 * 60, TimeUnit.SECONDS);
            
            // 记录成功登录日志
            logLoginAttempt(loginParam, user, true, "登录成功");

            result.success("登录成功", loginDomain);
            result.setData(loginDomain);
            
        } catch (AuthException e) {
            result.fail(e.getMessage());
        } catch (Exception e) {
            result.fail("登录失败: " + e.getMessage());
        }

        return result;
    }

    @Override
    public ResultDomain<String> logout(LoginDomain loginDomain) {
        ResultDomain<String> result = new ResultDomain<>();
        
        try {
            // TODO: 将token加入黑名单或从Redis中删除
            // 这里可以实现token黑名单机制
            
            result.success("退出登录成功", (String)null);
        } catch (Exception e) {
            result.fail("退出登录失败: " + e.getMessage());
        }

        return result;
    }

    /**
     * @description    自动检测登录类型
     * @param    loginParam 登录参数
     * @return    String 登录类型
     * @author    yslg
     * @since 2025-09-28
     */
    private String detectLoginType(LoginParam loginParam) {
        if (StringUtils.hasText(loginParam.getLoginType())) {
            return loginParam.getLoginType();
        }
        if (StringUtils.hasText(loginParam.getPassword())) {
            return "password";
        }
        if (StringUtils.hasText(loginParam.getEmail())) {
            return "email";
        }
        if (StringUtils.hasText(loginParam.getUsername())) {
            return "username";
        }
        if (StringUtils.hasText(loginParam.getPhone())) {
            return "phone";
        }
        if (StringUtils.hasText(loginParam.getWechatID())) {
            return "wechat";
        }

        throw new AuthException("INVALID_LOGIN_TYPE", "无法确定登录类型");
    }

    /**
     * @description    构建登录域对象
     * @param    user 用户对象
     * @param    loginType 登录类型
     * @return    LoginDomain 登录域对象
     * @author    yslg
     * @since 2025-09-28
     */
    private LoginDomain buildLoginDomain(TbSysUser user, String loginType, String ipAddress) {
        LoginDomain loginDomain = new LoginDomain();
        loginDomain.setUser(user);
        loginDomain.setLoginType(loginType);
        loginDomain.setLoginTime(new Date());
        loginDomain.setIpAddress(ipAddress);
        // 获取用户角色和权限（如果服务可用）
        try {
            ResultDomain<DeptRoleVO> resultDomain = roleService.getDeptRolesByUserId(user.getID());
            if (resultDomain.isSuccess()) {
                List<DeptRoleVO> roles = resultDomain.getDataList();
                loginDomain.setRoles(roles);
            } else {
                loginDomain.setRoles(new ArrayList<>());
            }
        } catch (Exception e) {
            loginDomain.setRoles(new ArrayList<>());
        }

        try {
            ResultDomain<TbSysPermission> resultDomain = permissionService.getPermissionsByUserId(user.getID());
            if (resultDomain.isSuccess()) {
                List<TbSysPermission> permissions = resultDomain.getDataList();
                loginDomain.setPermissions(permissions);
            } else {
                loginDomain.setPermissions(new ArrayList<>());
            }
        } catch (Exception e) {
            loginDomain.setPermissions(new ArrayList<>());
        }

        try {
            ResultDomain<TbSysMenu> resultDomain = menuService.getMenusByUserId(user.getID());
            if (resultDomain.isSuccess()) {
                List<TbSysMenu> menus = resultDomain.getDataList();
                loginDomain.setMenus(menus);
            } else {
                loginDomain.setMenus(new ArrayList<>());
            }
        } catch (Exception e) {
            loginDomain.setMenus(new ArrayList<>());
        }
        
        return loginDomain;
    }

    /**
     * @description    记录登录日志
     * @param    loginParam 登录参数
     * @param    user 用户对象
     * @param    success 是否成功
     * @param    message 消息
     * @author    yslg
     * @since 2025-09-28
     */
    private void logLoginAttempt(LoginParam loginParam, TbSysUser user, boolean success, String message) {
        TbSysLoginLog loginLog = new TbSysLoginLog();
        
        // 使用IDUtils生成登录日志ID
        loginLog.setID(IDUtils.generateID());
        
        if (user != null) {
            loginLog.setUserID(user.getID());
            loginLog.setUsername(user.getUsername());
        }
        // 注意：实际生产中不应记录密码
        // loginLog.setPassword(loginParam.getPassword()); 
        loginLog.setStatus(success ? 1 : 0);
        loginLog.setMessage(message);
        loginLog.setLoginTime(new Date().toString());
        
        loginLogService.saveLoginLog(loginLog);
    }
}
