package com.erp.user.service.auth.impl;

import com.erp.user.dto.auth.*;
import com.erp.user.entity.User;
import com.erp.user.entity.auth.AuthToken;
import com.erp.user.entity.auth.LoginDevice;
import com.erp.user.exception.auth.AuthException;
import com.erp.user.repository.UserRepository;
import com.erp.user.security.JwtTokenProvider;
import com.erp.user.service.auth.AuthService;
import com.erp.user.service.auth.CaptchaService;
import com.erp.user.service.auth.DeviceService;
import com.erp.user.service.auth.SmsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 认证服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider jwtTokenProvider;
    private final CaptchaService captchaService;
    private final SmsService smsService;
    private final DeviceService deviceService;
    
    @Override
    @Transactional
    public AuthResponse login(LoginRequest request, String ip, String userAgent) {
        // 验证图形验证码
        if (request.getCaptchaKey() != null && request.getCaptchaCode() != null) {
            if (!captchaService.verify(request.getCaptchaKey(), request.getCaptchaCode())) {
                throw new AuthException("图形验证码错误");
            }
        }
        
        // 查找用户
        User user = userRepository.findByUsername(request.getUsername());
        if (user == null) {
            throw new AuthException("用户名或密码错误");
        }
        
        // 验证密码
        if (!passwordEncoder.matches(request.getPassword(), user.getPasswordHash())) {
            throw new AuthException("用户名或密码错误");
        }
        
        // 检查用户状态
        if (!user.isEnabled()) {
            throw new AuthException("用户已被禁用");
        }
        
        // 创建设备记录
        LoginDevice device = deviceService.createDevice(
                user.getId(), user.getTenantId(),
                parseDeviceName(userAgent), parseDeviceType(userAgent),
                null, ip, null, userAgent
        );
        
        // 生成Token
        AuthToken authToken = jwtTokenProvider.generateToken(
                user.getId(), user.getTenantId(), user.getUsername(),
                device.getId(), device.getDeviceName(), device.getDeviceType(),
                ip, null
        );
        
        // 更新用户最后登录信息
        user.setLastLoginAt(LocalDateTime.now());
        user.setLastLoginIp(ip);
        userRepository.updateById(user);
        
        log.info("用户登录成功: userId={}, username={}, ip={}", user.getId(), user.getUsername(), ip);
        
        return buildAuthResponse(authToken);
    }
    
    @Override
    @Transactional
    public AuthResponse register(RegisterRequest request, String ip, String userAgent) {
        // 验证密码确认
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            throw new AuthException("两次密码输入不一致");
        }
        
        // 验证图形验证码
        if (request.getCaptchaKey() != null && request.getCaptchaCode() != null) {
            if (!captchaService.verify(request.getCaptchaKey(), request.getCaptchaCode())) {
                throw new AuthException("图形验证码错误");
            }
        }
        
        // 验证短信验证码（如果有手机号）
        if (request.getPhone() != null && request.getSmsCode() != null) {
            if (!smsService.verifyCode(request.getPhone(), request.getSmsCode(), "register")) {
                throw new AuthException("短信验证码错误");
            }
        }
        
        // 检查用户名是否已存在
        User existingUser = userRepository.findByUsername(request.getUsername());
        if (existingUser != null) {
            throw new AuthException("用户名已存在");
        }
        
        // 检查手机号是否已存在
        if (request.getPhone() != null) {
            User phoneUser = userRepository.findByPhone(request.getPhone());
            if (phoneUser != null) {
                throw new AuthException("手机号已被注册");
            }
        }
        
        // 创建用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
        user.setEmail(request.getEmail());
        user.setPhone(request.getPhone());
        user.setRealName(request.getRealName());
        user.setTenantId(1L); // 默认租户
        user.setStatus(1);
        user.setSuperAdmin(false);
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());
        
        userRepository.insert(user);
        
        // 创建设备记录
        LoginDevice device = deviceService.createDevice(
                user.getId(), user.getTenantId(),
                parseDeviceName(userAgent), parseDeviceType(userAgent),
                null, ip, null, userAgent
        );
        
        // 生成Token
        AuthToken authToken = jwtTokenProvider.generateToken(
                user.getId(), user.getTenantId(), user.getUsername(),
                device.getId(), device.getDeviceName(), device.getDeviceType(),
                ip, null
        );
        
        log.info("用户注册成功: userId={}, username={}", user.getId(), user.getUsername());
        
        return buildAuthResponse(authToken);
    }
    
    @Override
    public void logout(String token) {
        jwtTokenProvider.revokeToken(token);
        log.info("用户登出: token={}", token.substring(0, Math.min(10, token.length())) + "...");
    }
    
    @Override
    public AuthResponse refresh(String refreshToken) {
        AuthToken newToken = jwtTokenProvider.refreshToken(refreshToken);
        if (newToken == null) {
            throw new AuthException("刷新令牌无效或已过期");
        }
        return buildAuthResponse(newToken);
    }
    
    @Override
    @Transactional
    public AuthResponse smsLogin(SmsLoginRequest request, String ip, String userAgent) {
        // 验证短信验证码
        if (!smsService.verifyCode(request.getPhone(), request.getCode(), "login")) {
            throw new AuthException("短信验证码错误");
        }
        
        // 查找用户
        User user = userRepository.findByPhone(request.getPhone());
        if (user == null) {
            throw new AuthException("该手机号未注册");
        }
        
        // 检查用户状态
        if (!user.isEnabled()) {
            throw new AuthException("用户已被禁用");
        }
        
        // 创建设备记录
        LoginDevice device = deviceService.createDevice(
                user.getId(), user.getTenantId(),
                parseDeviceName(userAgent), parseDeviceType(userAgent),
                null, ip, null, userAgent
        );
        
        // 生成Token
        AuthToken authToken = jwtTokenProvider.generateToken(
                user.getId(), user.getTenantId(), user.getUsername(),
                device.getId(), device.getDeviceName(), device.getDeviceType(),
                ip, null
        );
        
        log.info("短信登录成功: userId={}, phone={}, ip={}", user.getId(), request.getPhone(), ip);
        
        return buildAuthResponse(authToken);
    }
    
    @Override
    public List<LoginDevice> getUserDevices(Long userId) {
        return deviceService.getLoginDevices(userId);
    }
    
    @Override
    public void logoutAllDevices(Long userId) {
        jwtTokenProvider.revokeAllUserTokens(userId);
        deviceService.invalidateAllDevices(userId, null);
        log.info("用户登出所有设备: userId={}", userId);
    }
    
    @Override
    public AuthToken getCurrentAuth(String token) {
        return jwtTokenProvider.validateToken(token);
    }
    
    private AuthResponse buildAuthResponse(AuthToken authToken) {
        return AuthResponse.builder()
                .accessToken(authToken.getAccessToken())
                .refreshToken(authToken.getRefreshToken())
                .tokenType("Bearer")
                .expiresIn(jwtTokenProvider.getAccessTokenExpiry())
                .userId(authToken.getUserId())
                .username(authToken.getUsername())
                .tenantId(authToken.getTenantId())
                .build();
    }
    
    private String parseDeviceName(String userAgent) {
        if (userAgent == null) return "Unknown";
        if (userAgent.contains("Windows")) return "Windows PC";
        if (userAgent.contains("Mac")) return "Mac";
        if (userAgent.contains("iPhone")) return "iPhone";
        if (userAgent.contains("iPad")) return "iPad";
        if (userAgent.contains("Android")) return "Android";
        return "Unknown";
    }
    
    private String parseDeviceType(String userAgent) {
        if (userAgent == null) return "other";
        if (userAgent.contains("Windows") || userAgent.contains("Mac")) return "web";
        if (userAgent.contains("iPhone") || userAgent.contains("iPad")) return "ios";
        if (userAgent.contains("Android")) return "android";
        return "other";
    }
}
