package com.social.media.application.company.handler;

import com.social.media.application.company.command.UpdateCompanyPlanCommand;
import com.social.media.application.ports.CompanyRepository;
import com.social.media.domain.company.Company;
import com.social.media.domain.shared.enums.CompanyPlan;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import static com.social.media.domain.company.valueobject.CompanyPlan.BASICO;

/**
 * Handler for updating company plan.
 * Implements business logic for plan changes and validations.
 */
@Component
public class UpdateCompanyPlanHandler {
    
    private final CompanyRepository companyRepository;
    
    public UpdateCompanyPlanHandler(CompanyRepository companyRepository) {
        this.companyRepository = companyRepository;
    }
    
    @Transactional
    public void handle(UpdateCompanyPlanCommand command) {
        // Find existing company
        Company company = companyRepository.findById(command.companyId())
            .orElseThrow(() -> new IllegalArgumentException("Company not found with ID: " + command.companyId()));
        
        // Validate new plan
        CompanyPlan newPlan;
        try {
            newPlan = CompanyPlan.valueOf(command.newPlan().toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid company plan: " + command.newPlan());
        }
        
        // Validate business rules for plan change
        validatePlanChangeRules(company, newPlan);
        
        // Update company plan - For now, we'll need to implement the plan change logic
        // TODO: Implement changePlan method in Company entity
        // company.changePlan(newPlan);
        
        // Save updated company
        companyRepository.save(company);
        
        // TODO: Publish domain event for plan change
        // publishPlanChangedEvent(company, newPlan, command.updatedByUserId());
    }
    
    private void validatePlanChangeRules(Company company, CompanyPlan newPlan) {
        CompanyPlan currentPlan = company.getActivePlan();
        
        // Business rule: Cannot downgrade if company has exceeded limits of new plan
        if (isDowngrade(currentPlan, newPlan)) {
            validateDowngradeAllowed(company, newPlan);
        }
        
        // Business rule: Company must be active to change plans
        if (!company.isActive()) {
            throw new IllegalArgumentException("Cannot change plan for inactive company");
        }
    }
    
    private boolean isDowngrade(CompanyPlan currentPlan, CompanyPlan newPlan) {
        // Simple hierarchy: BASIC < PROFESSIONAL < ENTERPRISE
        int currentLevel = getPlanLevel(currentPlan);
        int newLevel = getPlanLevel(newPlan);
        return newLevel < currentLevel;
    }
    
    private int getPlanLevel(CompanyPlan plan) {
        return switch (plan) {
            case BASIC -> 1;
            case PROFESSIONAL -> 2;
            case ENTERPRISE -> 3;
            case CUSTOM -> 4;
        };
    }
    
    private void validateDowngradeAllowed(Company company, CompanyPlan newPlan) {
        // TODO: Implement validation based on current usage
        // - Check number of users vs plan limit
        // - Check number of social accounts vs plan limit
        // - Check storage usage vs plan limit
        // For now, just validate the company has no excessive usage
        
        // Example validation (should be implemented based on actual usage data):
        // int userCount = userRepository.countByCompanyId(company.getId());
        // if (userCount > newPlan.getMaxUsers()) {
        //     throw new IllegalArgumentException("Cannot downgrade: company has more users than allowed in " + newPlan + " plan");
        // }
    }
    
    // TODO: Implement event publishing
    // private void publishPlanChangedEvent(Company company, CompanyPlan newPlan, UUID updatedByUserId) {
    //     CompanyPlanChangedEvent event = new CompanyPlanChangedEvent(
    //         company.getId(),
    //         company.getPlan(),
    //         newPlan,
    //         updatedByUserId,
    //         LocalDateTime.now()
    //     );
    //     eventPublisher.publish(event);
    // }
}
