package com.gcsc.connection.user.service;

import com.gcsc.connection.common.exception.BusinessException;
import com.gcsc.connection.common.exception.ErrorCode;
import com.gcsc.connection.tenant.entity.SnpTenant;
import com.gcsc.connection.tenant.repository.SnpTenantRepository;
import com.gcsc.connection.user.dto.CreateUserRequest;
import com.gcsc.connection.user.dto.UpdateUserRequest;
import com.gcsc.connection.user.dto.UserResponse;
import com.gcsc.connection.user.entity.SnpUser;
import com.gcsc.connection.user.entity.UserRole;
import com.gcsc.connection.user.repository.SnpUserRepository;
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.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserService {

    private final SnpUserRepository snpUserRepository;
    private final SnpTenantRepository snpTenantRepository;
    private final PasswordEncoder passwordEncoder;

    /**
     * 전체 사용자 목록 조회
     */
    @Transactional(readOnly = true)
    public List<UserResponse> getUsers() {
        return snpUserRepository.findAll().stream()
            .map(UserResponse::from)
            .toList();
    }

    /**
     * 사용자 단건 조회
     */
    @Transactional(readOnly = true)
    public UserResponse getUser(Long id) {
        SnpUser user = snpUserRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
        return UserResponse.from(user);
    }

    /**
     * 사용자 생성
     */
    @Transactional
    public UserResponse createUser(CreateUserRequest request) {
        if (snpUserRepository.existsByLoginId(request.loginId())) {
            throw new BusinessException(ErrorCode.USER_LOGIN_ID_DUPLICATE);
        }

        SnpTenant tenant = null;
        if (request.tenantId() != null) {
            tenant = snpTenantRepository.findById(request.tenantId())
                .orElseThrow(() -> new BusinessException(ErrorCode.TENANT_NOT_FOUND));
        }

        SnpUser user = SnpUser.builder()
            .tenant(tenant)
            .loginId(request.loginId())
            .passwordHash(passwordEncoder.encode(request.password()))
            .userName(request.userName())
            .email(request.email())
            .role(UserRole.valueOf(request.role()))
            .build();

        SnpUser saved = snpUserRepository.save(user);
        log.info("사용자 생성 완료: {}", saved.getLoginId());
        return UserResponse.from(saved);
    }

    /**
     * 사용자 수정
     */
    @Transactional
    public UserResponse updateUser(Long id, UpdateUserRequest request) {
        SnpUser user = snpUserRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));

        SnpTenant tenant = null;
        if (request.tenantId() != null) {
            tenant = snpTenantRepository.findById(request.tenantId())
                .orElseThrow(() -> new BusinessException(ErrorCode.TENANT_NOT_FOUND));
        }

        UserRole role = request.role() != null ? UserRole.valueOf(request.role()) : null;
        user.update(tenant, request.userName(), request.email(), role, request.isActive());

        if (request.password() != null && !request.password().isBlank()) {
            user.updatePassword(passwordEncoder.encode(request.password()));
        }

        log.info("사용자 수정 완료: {}", user.getLoginId());
        return UserResponse.from(user);
    }

    /**
     * 사용자 비활성화 (소프트 삭제)
     */
    @Transactional
    public void deactivateUser(Long id) {
        SnpUser user = snpUserRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
        user.deactivate();
        log.info("사용자 비활성화 완료: {}", user.getLoginId());
    }
}
