package com.saas.admin.service;

import com.saas.admin.dto.AuthResponse;
import com.saas.admin.dto.LoginRequest;
import com.saas.admin.dto.RegisterRequest;
import com.saas.admin.entity.Tenant;
import com.saas.admin.entity.User;
import com.saas.admin.repository.TenantRepository;
import com.saas.admin.repository.UserRepository;
import com.saas.shared.core.TenantContext;
import com.saas.shared.enums.UserType;
import com.saas.shared.exception.BusinessException;
import com.saas.shared.exception.ErrorCode;
import com.saas.shared.security.JwtTokenProvider;
import com.saas.shared.util.SlugUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
public class AuthService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private TenantRepository tenantRepository;
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private JwtTokenProvider tokenProvider;
    
    @Autowired
    private TenantSchemaService tenantSchemaService;
    
    @Value("${multitenancy.tenant-schema-prefix}")
    private String tenantSchemaPrefix;
    
    @Transactional
    public AuthResponse register(RegisterRequest request) {
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException(ErrorCode.USER_ALREADY_EXISTS, "Email already exists");
        }
        
        String tenantId = UUID.randomUUID().toString();
        String schemaName = SlugUtils.toTenantDatabaseName(request.getTenantName(), tenantSchemaPrefix);
        
        if (tenantRepository.existsBySchemaName(schemaName)) {
            throw new BusinessException(ErrorCode.TENANT_ALREADY_EXISTS, "Tenant name already exists. Please choose a different name.");
        }
        
        TenantContext.setTenantId("admin");
        
        Tenant tenant = new Tenant();
        tenant.setTenantId(tenantId);
        tenant.setTenantName(request.getTenantName());
        tenant.setSchemaName(schemaName);
        tenantRepository.save(tenant);
        
        User user = new User();
        user.setEmail(request.getEmail());
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setFirstName(request.getFirstName());
        user.setLastName(request.getLastName());
        user.setUserType(UserType.TENANT_USER);
        user.setTenantId(tenantId);
        user.setRole("ADMIN");
        userRepository.save(user);
        
        tenantSchemaService.createTenantDatabaseAndTables(tenant, user);
        
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
        );
        
        String token = tokenProvider.generateToken(authentication, tenantId, schemaName, UserType.TENANT_USER.name());
        
        TenantContext.clear();
        
        return new AuthResponse(token, tenantId, user.getEmail());
    }
    
    public AuthResponse login(LoginRequest request) {
        TenantContext.setTenantId("admin");
        
        User user = userRepository.findByEmail(request.getEmail())
            .orElseThrow(() -> new BusinessException(ErrorCode.INVALID_CREDENTIALS, "Invalid credentials"));
        
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
        );
        
        String token;
        if (user.getUserType() == UserType.SYSTEM_ADMIN) {
            token = tokenProvider.generateToken(authentication, null, null, UserType.SYSTEM_ADMIN.name());
        } else {
            Tenant tenant = tenantRepository.findByTenantId(user.getTenantId())
                .orElseThrow(() -> new BusinessException(ErrorCode.TENANT_NOT_FOUND, "Tenant not found"));
            token = tokenProvider.generateToken(authentication, user.getTenantId(), tenant.getSchemaName(), UserType.TENANT_USER.name());
        }
        
        TenantContext.clear();
        
        return new AuthResponse(token, user.getTenantId(), user.getEmail());
    }
}
