package com.saas.tenant.service;

import com.saas.shared.dto.common.PageResponse;
import com.saas.shared.dto.mapper.UserMapper;
import com.saas.shared.exception.BusinessException;
import com.saas.shared.exception.ErrorCode;
import com.saas.shared.exception.ResourceNotFoundException;
import com.saas.tenant.dto.request.CreateTenantUserRequest;
import com.saas.tenant.dto.request.UpdateTenantUserRequest;
import com.saas.tenant.dto.response.TenantUserResponse;
import com.saas.tenant.entity.TenantUser;
import com.saas.tenant.repository.TenantUserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
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 TenantUserService {
    
    private final TenantUserRepository userRepository;
    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    
    @Transactional(transactionManager = "tenantTransactionManager")
    public TenantUserResponse createUser(CreateTenantUserRequest request) {
        log.info("Creating tenant user with email: {}", request.getEmail());
        
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException(ErrorCode.USER_ALREADY_EXISTS, 
                "User with email " + request.getEmail() + " already exists in this tenant");
        }
        
        TenantUser user = userMapper.toTenantUserEntity(request);
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setStatus("ACTIVE");
        
        TenantUser savedUser = userRepository.save(user);
        log.info("Tenant user created successfully with ID: {}", savedUser.getId());
        
        return userMapper.toTenantUserResponse(savedUser);
    }
    
    @Transactional(transactionManager = "tenantTransactionManager", readOnly = true)
    public TenantUserResponse getUserById(Long id) {
        log.debug("Fetching tenant user with ID: {}", id);
        return userRepository.findById(id)
            .map(userMapper::toTenantUserResponse)
            .orElseThrow(() -> new ResourceNotFoundException("User", id));
    }
    
    @Transactional(transactionManager = "tenantTransactionManager", readOnly = true)
    public List<TenantUserResponse> getAllUsers() {
        log.debug("Fetching all tenant users");
        return userMapper.toTenantUserResponseList(userRepository.findAll());
    }
    
    @Transactional(transactionManager = "tenantTransactionManager", readOnly = true)
    public PageResponse<TenantUserResponse> getUsers(int page, int size) {
        log.debug("Fetching tenant users - page: {}, size: {}", page, size);
        Pageable pageable = PageRequest.of(page, size);
        Page<TenantUser> userPage = userRepository.findAll(pageable);
        
        return PageResponse.<TenantUserResponse>builder()
            .content(userMapper.toTenantUserResponseList(userPage.getContent()))
            .page(page)
            .size(size)
            .totalElements(userPage.getTotalElements())
            .totalPages(userPage.getTotalPages())
            .hasNext(userPage.hasNext())
            .hasPrevious(userPage.hasPrevious())
            .build();
    }
    
    @Transactional(transactionManager = "tenantTransactionManager")
    public TenantUserResponse updateUser(Long id, UpdateTenantUserRequest request) {
        log.info("Updating tenant user with ID: {}", id);
        
        TenantUser user = userRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("User", id));
        
        userMapper.updateTenantUserEntity(request, user);
        
        TenantUser updatedUser = userRepository.save(user);
        log.info("Tenant user updated successfully with ID: {}", updatedUser.getId());
        
        return userMapper.toTenantUserResponse(updatedUser);
    }
    
    @Transactional(transactionManager = "tenantTransactionManager")
    public void deleteUser(Long id) {
        log.info("Deleting tenant user with ID: {}", id);
        
        if (!userRepository.existsById(id)) {
            throw new ResourceNotFoundException("User", id);
        }
        
        userRepository.deleteById(id);
        log.info("Tenant user deleted successfully with ID: {}", id);
    }
}
