package com.kt.event.user.service.impl;

import com.kt.event.common.exception.BusinessException;
import com.kt.event.common.security.JwtTokenProvider;
import com.kt.event.user.dto.request.LoginRequest;
import com.kt.event.user.dto.response.LoginResponse;
import com.kt.event.user.dto.response.LogoutResponse;
import com.kt.event.user.entity.Store;
import com.kt.event.user.entity.User;
import com.kt.event.user.exception.UserErrorCode;
import com.kt.event.user.repository.StoreRepository;
import com.kt.event.user.repository.UserRepository;
import com.kt.event.user.service.AuthenticationService;
import com.kt.event.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Authentication Service 구현체
 *
 * 인증 관련 비즈니스 로직 구현
 *
 * @author Backend Developer
 * @since 1.0
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class AuthenticationServiceImpl implements AuthenticationService {

    private final UserRepository userRepository;
    private final StoreRepository storeRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider jwtTokenProvider;
    private final UserService userService;

    @Autowired(required = false)
    private RedisTemplate<String, Object> redisTemplate;

    public AuthenticationServiceImpl(UserRepository userRepository,
                                    StoreRepository storeRepository,
                                    PasswordEncoder passwordEncoder,
                                    JwtTokenProvider jwtTokenProvider,
                                    UserService userService) {
        this.userRepository = userRepository;
        this.storeRepository = storeRepository;
        this.passwordEncoder = passwordEncoder;
        this.jwtTokenProvider = jwtTokenProvider;
        this.userService = userService;
    }

    /**
     * 로그인
     *
     * UFR-USER-020: 로그인
     */
    @Override
    @Transactional(readOnly = false)
    public LoginResponse login(LoginRequest request) {
        // 1. 사용자 조회 (이메일 기반)
        User user = userRepository.findByEmail(request.getEmail())
                .orElseThrow(() -> new BusinessException(UserErrorCode.AUTH_FAILED.getErrorCode()));

        // 2. 비밀번호 검증
        if (!passwordEncoder.matches(request.getPassword(), user.getPasswordHash())) {
            throw new BusinessException(UserErrorCode.AUTH_FAILED.getErrorCode());
        }

        // 3. 매장 정보 조회
        Store store = storeRepository.findByUserId(user.getId()).orElse(null);
        UUID storeId = store != null ? store.getId() : null;

        // 4. JWT 토큰 생성
        String token = jwtTokenProvider.createAccessToken(
                user.getId(),
                storeId,
                user.getEmail(),
                user.getName(),
                List.of(user.getRole().name())
        );

        // 5. Redis 세션 저장 (TTL 7일)
        saveSession(token, user.getId(), user.getRole().name());

        // 6. 최종 로그인 시각 업데이트 (비동기)
        userService.updateLastLoginAt(user.getId());

        // 7. 응답 반환
        return LoginResponse.builder()
                .token(token)
                .userId(user.getId())
                .userName(user.getName())
                .role(user.getRole().name())
                .email(user.getEmail())
                .build();
    }

    /**
     * 로그아웃
     *
     * UFR-USER-040: 로그아웃
     */
    @Override
    public LogoutResponse logout(String token) {
        // 1. JWT 토큰 검증
        if (!jwtTokenProvider.validateToken(token)) {
            throw new BusinessException(UserErrorCode.AUTH_INVALID_TOKEN.getErrorCode());
        }

        // 2. Redis 세션 삭제 (Redis가 활성화된 경우에만)
        if (redisTemplate != null) {
            String sessionKey = "user:session:" + token;
            redisTemplate.delete(sessionKey);

            // 3. JWT Blacklist 추가 (남은 만료 시간만큼 TTL 설정)
            String blacklistKey = "jwt:blacklist:" + token;
            long remainingTime = jwtTokenProvider.getExpirationFromToken(token).getTime() - System.currentTimeMillis();
            if (remainingTime > 0) {
                redisTemplate.opsForValue().set(blacklistKey, "true", remainingTime, TimeUnit.MILLISECONDS);
            }
            log.debug("Redis session and blacklist updated for logout");
        } else {
            log.warn("Redis is disabled. Session not cleared from Redis.");
        }

        // 4. 응답 반환
        return LogoutResponse.builder()
                .success(true)
                .message("안전하게 로그아웃되었습니다")
                .build();
    }

    /**
     * Redis 세션 저장 (Redis가 활성화된 경우에만)
     *
     * @param token JWT 토큰
     * @param userId 사용자 ID
     * @param role 역할
     */
    private void saveSession(String token, UUID userId, String role) {
        if (redisTemplate != null) {
            String key = "user:session:" + token;
            String value = userId + ":" + role;
            redisTemplate.opsForValue().set(key, value, 7, TimeUnit.DAYS);
            log.debug("Redis session saved: userId={}", userId);
        } else {
            log.warn("Redis is disabled. Session not saved to Redis.");
        }
    }
}
