package com.emotion.service.impl;

import com.emotion.dto.request.AdminLoginRequest;
import com.emotion.dto.response.AdminAuthResponse;
import com.emotion.dto.response.AdminInfoResponse;
import com.emotion.entity.Admin;
import com.emotion.exception.AuthException;
import com.emotion.service.AdminAuthService;
import com.emotion.service.AdminService;
import com.emotion.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * 管理员认证服务实现类
 *
 * @author emotion-museum
 * @date 2025-10-27
 */
@Slf4j
@Service
public class AdminAuthServiceImpl implements AdminAuthService {

    @Autowired
    private AdminService adminService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private org.springframework.security.crypto.password.PasswordEncoder passwordEncoder;

    private static final String ADMIN_TOKEN_PREFIX = "admin_token:";
    private static final String ADMIN_REFRESH_TOKEN_PREFIX = "admin_refresh_token:";
    private static final int TOKEN_EXPIRE_HOURS = 24;
    private static final int REFRESH_TOKEN_EXPIRE_DAYS = 7;
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public AdminAuthResponse login(AdminLoginRequest request) {
        Admin admin = adminService.getByAccount(request.getAccount());
        
        if (admin == null) {
            throw new AuthException("账号或密码错误");
        }
        
        if (admin.getStatus() != 1) {
            throw new AuthException("账号已被禁用");
        }
        
        if (!passwordEncoder.matches(request.getPassword(), admin.getPassword())) {
            throw new AuthException("账号或密码错误");
        }
        
        log.info("管理员登录成功: account={}, adminId={}", request.getAccount(), admin.getId());
        
        String accessToken = generateAccessToken(admin);
        String refreshToken = generateRefreshToken(admin);
        
        updateLoginInfo(admin);
        
        AdminAuthResponse response = new AdminAuthResponse();
        response.setAccessToken(accessToken);
        response.setRefreshToken(refreshToken);
        response.setExpiresIn((long) TOKEN_EXPIRE_HOURS * 3600);
        response.setAdminInfo(convertToAdminInfoResponse(admin));
        response.setLoginTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
        
        return response;
    }

    @Override
    public AdminInfoResponse getCurrentAdminInfo(String adminId) {
        Admin admin = adminService.getById(adminId);
        if (admin == null) {
            throw new AuthException("管理员不存在");
        }
        return convertToAdminInfoResponse(admin);
    }

    @Override
    public boolean logout(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            String adminId = jwtUtil.getUserIdFromToken(token);
            
            if (adminId != null) {
                redisTemplate.delete(ADMIN_TOKEN_PREFIX + adminId);
                log.info("管理员登出成功: adminId={}", adminId);
                return true;
            }
        }
        return false;
    }

    @Override
    public AdminAuthResponse refreshToken(String refreshToken) {
        if (!jwtUtil.validateToken(refreshToken)) {
            throw new AuthException("刷新令牌无效或已过期");
        }
        
        String adminId = jwtUtil.getUserIdFromToken(refreshToken);
        String userType = jwtUtil.getUserTypeFromToken(refreshToken);
        
        if (!"admin".equals(userType)) {
            throw new AuthException("无效的刷新令牌");
        }
        
        String cachedToken = (String) redisTemplate.opsForValue().get(ADMIN_REFRESH_TOKEN_PREFIX + adminId);
        if (cachedToken == null || !cachedToken.equals(refreshToken)) {
            throw new AuthException("刷新令牌已失效");
        }
        
        Admin admin = adminService.getById(adminId);
        if (admin == null) {
            throw new AuthException("管理员不存在");
        }
        
        if (admin.getStatus() != 1) {
            throw new AuthException("账号已被禁用");
        }
        
        String newAccessToken = generateAccessToken(admin);
        String newRefreshToken = generateRefreshToken(admin);
        
        AdminAuthResponse response = new AdminAuthResponse();
        response.setAccessToken(newAccessToken);
        response.setRefreshToken(newRefreshToken);
        response.setExpiresIn((long) TOKEN_EXPIRE_HOURS * 3600);
        response.setAdminInfo(convertToAdminInfoResponse(admin));
        response.setLoginTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
        
        return response;
    }

    @Override
    public boolean validateToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            return false;
        }
        
        String token = authHeader.substring(7);
        if (!jwtUtil.validateToken(token)) {
            return false;
        }
        
        String userType = jwtUtil.getUserTypeFromToken(token);
        return "admin".equals(userType);
    }

    @Override
    public String getAdminIdFromToken(String token) {
        return jwtUtil.getUserIdFromToken(token);
    }

    private String generateAccessToken(Admin admin) {
        String token = jwtUtil.generateToken(admin.getId(), admin.getUsername(), "admin");
        redisTemplate.opsForValue().set(
            ADMIN_TOKEN_PREFIX + admin.getId(),
            token,
            TOKEN_EXPIRE_HOURS,
            TimeUnit.HOURS
        );
        return token;
    }

    private String generateRefreshToken(Admin admin) {
        String token = jwtUtil.generateRefreshToken(admin.getId(), admin.getUsername(), "admin");
        redisTemplate.opsForValue().set(
            ADMIN_REFRESH_TOKEN_PREFIX + admin.getId(),
            token,
            REFRESH_TOKEN_EXPIRE_DAYS,
            TimeUnit.DAYS
        );
        return token;
    }

    private void updateLoginInfo(Admin admin) {
        admin.setLastLoginTime(LocalDateTime.now());
        admin.setLoginCount(admin.getLoginCount() == null ? 1 : admin.getLoginCount() + 1);
        adminService.updateById(admin);
    }

    private AdminInfoResponse convertToAdminInfoResponse(Admin admin) {
        AdminInfoResponse response = new AdminInfoResponse();
        BeanUtils.copyProperties(admin, response);
        return response;
    }
}
