package com.social.media.application.usecases.user;

import com.social.media.application.ports.out.CompanyRepositoryPort;
import com.social.media.application.ports.out.UserRepositoryPort;
import com.social.media.domain.company.entities.Company;
import com.social.media.domain.user.entities.User;
import com.social.media.domain.user.valueobjects.UserRole;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Use case for creating a new user.
 * 
 * Handles the business logic for user registration including
 * validation, company limits check, and password hashing.
 * 
 * @author Social Media Manager Team
 * @since 2.0.0
 */
@Service
@RequiredArgsConstructor
@Transactional
public class CreateUserUseCase {
    
    private final UserRepositoryPort userRepository;
    private final CompanyRepositoryPort companyRepository;
    private final PasswordEncoder passwordEncoder;
    
    public record CreateUserCommand(
        String companyUuid,
        String firstName,
        String lastName,
        String email,
        String password,
        UserRole.RoleType roleType,
        String timezone,
        String language
    ) {}
    
    public record CreateUserResult(
        String userUuid,
        String email,
        String fullName,
        UserRole.RoleType roleType,
        String companyName,
        boolean emailVerified
    ) {}
    
    /**
     * Execute the create user use case
     */
    public CreateUserResult execute(CreateUserCommand command) {
        // Validate command
        validateCreateUserCommand(command);
        
        // Find company
        Company company = companyRepository.findByUuid(command.companyUuid())
            .orElseThrow(() -> new IllegalArgumentException("Company not found"));
        
        // Check if company is active
        if (!company.isActive()) {
            throw new IllegalArgumentException("Company is not active");
        }
        
        // Check if user with email already exists
        if (userRepository.existsByEmail(command.email())) {
            throw new IllegalArgumentException("User with this email already exists");
        }
        
        // Check company user limit
        long currentUserCount = userRepository.countActiveByCompanyId(company.getId().getValueAsLong());
        if (currentUserCount >= company.getEffectiveMaxUsers()) {
            throw new IllegalArgumentException("Company has reached maximum user limit");
        }
        
        // Hash password
        String hashedPassword = passwordEncoder.encode(command.password());
        
        // Create new user
        User user = User.create(
            company.getId(),
            command.firstName(),
            command.lastName(),
            command.email(),
            hashedPassword,
            command.roleType()
        );
        
        // Save user
        User savedUser = userRepository.save(user);
        
        // Return result
        return new CreateUserResult(
            savedUser.getUserUuid(),
            savedUser.getEmail(),
            savedUser.getFullName(),
            savedUser.getRole(),
            company.getName(),
            savedUser.getEmailVerified()
        );
    }
    
    /**
     * Validate the create user command
     */
    private void validateCreateUserCommand(CreateUserCommand command) {
        if (command.companyUuid() == null || command.companyUuid().trim().isEmpty()) {
            throw new IllegalArgumentException("Company UUID is required");
        }
        
        if (command.firstName() == null || command.firstName().trim().isEmpty()) {
            throw new IllegalArgumentException("First name is required");
        }
        
        if (command.lastName() == null || command.lastName().trim().isEmpty()) {
            throw new IllegalArgumentException("Last name is required");
        }
        
        if (command.email() == null || command.email().trim().isEmpty()) {
            throw new IllegalArgumentException("Email is required");
        }
        
        if (command.password() == null || command.password().isEmpty()) {
            throw new IllegalArgumentException("Password is required");
        }
        
        if (command.roleType() == null) {
            throw new IllegalArgumentException("Role type is required");
        }
        
        if (command.timezone() == null || command.timezone().trim().isEmpty()) {
            throw new IllegalArgumentException("Timezone is required");
        }
        
        if (command.language() == null || command.language().trim().isEmpty()) {
            throw new IllegalArgumentException("Language is required");
        }
        
        // Validate password strength
        validatePasswordStrength(command.password());
        
        // Validate timezone format
        if (!isValidTimezone(command.timezone())) {
            throw new IllegalArgumentException("Invalid timezone format");
        }
        
        // Validate language format
        if (!isValidLanguage(command.language())) {
            throw new IllegalArgumentException("Invalid language format");
        }
    }
    
    /**
     * Validate password strength
     */
    private void validatePasswordStrength(String password) {
        if (password.length() < 8) {
            throw new IllegalArgumentException("Password must be at least 8 characters long");
        }
        
        if (!password.matches(".*[A-Z].*")) {
            throw new IllegalArgumentException("Password must contain at least one uppercase letter");
        }
        
        if (!password.matches(".*[a-z].*")) {
            throw new IllegalArgumentException("Password must contain at least one lowercase letter");
        }
        
        if (!password.matches(".*[0-9].*")) {
            throw new IllegalArgumentException("Password must contain at least one digit");
        }
        
        if (!password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*")) {
            throw new IllegalArgumentException("Password must contain at least one special character");
        }
    }
    
    /**
     * Basic timezone validation
     */
    private boolean isValidTimezone(String timezone) {
        try {
            java.time.ZoneId.of(timezone);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * Basic language validation (ISO 639-1 codes)
     */
    private boolean isValidLanguage(String language) {
        return language.matches("^[a-z]{2}$");
    }
}
