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.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 lombok.extern.slf4j.Slf4j;

import java.util.UUID;

@Service
@Slf4j
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, user.getId().toString(), tenantId, user.getEmail(),
                                UserType.TENANT_USER.name(),
                                user.getFirstName(), user.getLastName());
        }

        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;
                String userType;
                if (user.getUserType() == UserType.SYSTEM_ADMIN) {
                        token = tokenProvider.generateToken(authentication, null, null, UserType.SYSTEM_ADMIN.name());
                        userType = UserType.SYSTEM_ADMIN.name();
                        log.info("🔐 ADMIN LOGIN - Generated token without tenant/schema");
                } else {
                        Tenant tenant = tenantRepository.findByTenantId(user.getTenantId())
                                        .orElseThrow(() -> new BusinessException(ErrorCode.TENANT_NOT_FOUND,
                                                        "Tenant not found"));

                        // CRITICAL: Validate schemaName is not null/empty
                        if (tenant.getSchemaName() == null || tenant.getSchemaName().trim().isEmpty()) {
                                log.error("❌ CRITICAL BUG: Tenant {} has NULL or EMPTY schemaName in database! tenantId: {}",
                                                tenant.getTenantName(), user.getTenantId());
                                throw new BusinessException(ErrorCode.TENANT_NOT_FOUND,
                                                "Tenant configuration error: Missing schema name. Please contact support.");
                        }

                        log.info("🔐 TENANT LOGIN - tenantId: {}, schemaName: {}, email: {}",
                                        user.getTenantId(), tenant.getSchemaName(), user.getEmail());

                        token = tokenProvider.generateToken(authentication, user.getTenantId(), tenant.getSchemaName(),
                                        UserType.TENANT_USER.name());
                        userType = UserType.TENANT_USER.name();

                        log.info("✅ TENANT TOKEN GENERATED - tenantId: {}, schemaName: {}",
                                        user.getTenantId(), tenant.getSchemaName());
                }

                TenantContext.clear();

                return new AuthResponse(token, user.getId().toString(), user.getTenantId(), user.getEmail(), userType,
                                user.getFirstName(), user.getLastName());
        }
}
