package com.social.media.domain.user;

import com.social.media.domain.shared.BaseValueObject;
import com.social.media.domain.shared.enums.UserType;
import lombok.EqualsAndHashCode;
import lombok.Getter;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * Value Object representing user permissions in the system.
 * 
 * Encapsulates all permission-related logic and provides type-safe access
 * to different permission categories. Permissions are organized hierarchically
 * and can include custom permissions for specific business needs.
 * 
 * @author Social Media Manager Team
 * @version 2.0
 * @since 2025-01-01
 */
@Getter
@EqualsAndHashCode(callSuper = false)
public final class UserPermissions extends BaseValueObject {
    
    // Core system permissions
    private final boolean canManageUsers;
    private final boolean canManageCompany;
    private final boolean canManageSocialAccounts;
    private final boolean canCreatePosts;
    private final boolean canSchedulePosts;
    private final boolean canPublishPosts;
    private final boolean canViewAnalytics;
    private final boolean canManageBots;
    private final boolean canAccessSettings;
    
    // Custom permissions for extensibility
    private final Map<String, Boolean> customPermissions;
    
    /**
     * Creates UserPermissions with all permissions specified.
     */
    public UserPermissions(boolean canManageUsers, boolean canManageCompany, 
                          boolean canManageSocialAccounts, boolean canCreatePosts,
                          boolean canSchedulePosts, boolean canPublishPosts,
                          boolean canViewAnalytics, boolean canManageBots,
                          boolean canAccessSettings, Map<String, Boolean> customPermissions) {
        this.canManageUsers = canManageUsers;
        this.canManageCompany = canManageCompany;
        this.canManageSocialAccounts = canManageSocialAccounts;
        this.canCreatePosts = canCreatePosts;
        this.canSchedulePosts = canSchedulePosts;
        this.canPublishPosts = canPublishPosts;
        this.canViewAnalytics = canViewAnalytics;
        this.canManageBots = canManageBots;
        this.canAccessSettings = canAccessSettings;
        this.customPermissions = customPermissions != null ? 
                                 new HashMap<>(customPermissions) : new HashMap<>();
        
        super.validate();
    }
    
    /**
     * Creates UserPermissions based on user type with default permissions.
     * 
     * @param userType the user type to base permissions on
     * @return UserPermissions instance with appropriate permissions
     */
    public static UserPermissions forUserType(UserType userType) {
        return switch (userType) {
            case SUPER_ADMIN -> createSuperAdminPermissions();
            case ADMIN -> createCompanyAdminPermissions();
            case MANAGER -> createManagerPermissions();
            case USER -> createUserPermissions();
            case VIEWER -> createViewerPermissions();
        };
    }
    
    /**
     * Creates a custom UserPermissions instance.
     * 
     * @return a new builder instance
     */
    public static Builder builder() {
        return new Builder();
    }
    
    /**
     * Gets a custom permission value.
     * 
     * @param permissionName the name of the custom permission
     * @return the permission value, or false if not set
     */
    public boolean getCustomPermission(String permissionName) {
        return customPermissions.getOrDefault(permissionName, false);
    }
    
    /**
     * Gets all custom permission names.
     * 
     * @return set of custom permission names
     */
    public Set<String> getCustomPermissionNames() {
        return customPermissions.keySet();
    }
    
    /**
     * Checks if this permission set includes all permissions from another set.
     * 
     * @param other the other permission set to compare
     * @return true if this includes all permissions from other
     */
    public boolean includes(UserPermissions other) {
        // Check core permissions
        if (other.canManageUsers && !this.canManageUsers) return false;
        if (other.canManageCompany && !this.canManageCompany) return false;
        if (other.canManageSocialAccounts && !this.canManageSocialAccounts) return false;
        if (other.canCreatePosts && !this.canCreatePosts) return false;
        if (other.canSchedulePosts && !this.canSchedulePosts) return false;
        if (other.canPublishPosts && !this.canPublishPosts) return false;
        if (other.canViewAnalytics && !this.canViewAnalytics) return false;
        if (other.canManageBots && !this.canManageBots) return false;
        if (other.canAccessSettings && !this.canAccessSettings) return false;
        
        // Check custom permissions
        for (Map.Entry<String, Boolean> entry : other.customPermissions.entrySet()) {
            if (entry.getValue() && !this.getCustomPermission(entry.getKey())) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Creates a new UserPermissions with additional custom permission.
     * 
     * @param permissionName the custom permission name
     * @param value the permission value
     * @return new UserPermissions instance
     */
    public UserPermissions withCustomPermission(String permissionName, boolean value) {
        Map<String, Boolean> newCustomPermissions = new HashMap<>(this.customPermissions);
        newCustomPermissions.put(permissionName, value);
        
        return new UserPermissions(canManageUsers, canManageCompany, canManageSocialAccounts,
                                  canCreatePosts, canSchedulePosts, canPublishPosts,
                                  canViewAnalytics, canManageBots, canAccessSettings,
                                  newCustomPermissions);
    }
    
    /**
     * Creates permissions for Super Admin users.
     */
    private static UserPermissions createSuperAdminPermissions() {
        Map<String, Boolean> customPermissions = new HashMap<>();
        customPermissions.put("canAccessSystemSettings", true);
        customPermissions.put("canManageAllCompanies", true);
        customPermissions.put("canViewSystemLogs", true);
        customPermissions.put("canManageIntegrations", true);
        
        return new UserPermissions(true, true, true, true, true, true, 
                                  true, true, true, customPermissions);
    }
    
    /**
     * Creates permissions for Company Admin users.
     */
    private static UserPermissions createCompanyAdminPermissions() {
        Map<String, Boolean> customPermissions = new HashMap<>();
        customPermissions.put("canManageBilling", true);
        customPermissions.put("canViewCompanyAnalytics", true);
        customPermissions.put("canManageTeam", true);
        
        return new UserPermissions(true, true, true, true, true, true, 
                                  true, true, true, customPermissions);
    }
    
    /**
     * Creates permissions for Manager users.
     */
    private static UserPermissions createManagerPermissions() {
        Map<String, Boolean> customPermissions = new HashMap<>();
        customPermissions.put("canApprovePosts", true);
        customPermissions.put("canManageContentCalendar", true);
        
        return new UserPermissions(true, false, false, true, true, true, 
                                  true, true, false, customPermissions);
    }
    
    /**
     * Creates permissions for regular User users.
     */
    private static UserPermissions createUserPermissions() {
        Map<String, Boolean> customPermissions = new HashMap<>();
        
        return new UserPermissions(false, false, false, true, true, false, 
                                  true, false, false, customPermissions);
    }
    
    /**
     * Creates permissions for Viewer users.
     */
    private static UserPermissions createViewerPermissions() {
        Map<String, Boolean> customPermissions = new HashMap<>();
        
        return new UserPermissions(false, false, false, false, false, false, 
                                  true, false, false, customPermissions);
    }
    
    /**
     * Creates permissions for API users.
     */
    private static UserPermissions createApiPermissions() {
        Map<String, Boolean> customPermissions = new HashMap<>();
        customPermissions.put("canAccessApi", true);
        
        return new UserPermissions(false, false, false, false, false, false, 
                                  false, false, false, customPermissions);
    }
    
    @Override
    public void validate() {
        // Validation rules for permission consistency
        
        // If can manage users, should also be able to access settings
        if (canManageUsers && !canAccessSettings) {
            throw new IllegalArgumentException("Users who can manage users should also access settings");
        }
        
        // If can manage company, should also be able to access settings
        if (canManageCompany && !canAccessSettings) {
            throw new IllegalArgumentException("Users who can manage company should also access settings");
        }
        
        // If can publish posts, should also be able to create and schedule posts
        if (canPublishPosts && (!canCreatePosts || !canSchedulePosts)) {
            throw new IllegalArgumentException("Users who can publish posts should also create and schedule posts");
        }
        
        // If can manage bots, should also be able to view analytics
        if (canManageBots && !canViewAnalytics) {
            throw new IllegalArgumentException("Users who can manage bots should also view analytics");
        }
        
        // Custom permission names should not be null or empty
        for (String permissionName : customPermissions.keySet()) {
            if (permissionName == null || permissionName.trim().isEmpty()) {
                throw new IllegalArgumentException("Custom permission names cannot be null or empty");
            }
        }
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        UserPermissions that = (UserPermissions) obj;
        return canManageUsers == that.canManageUsers &&
               canManageCompany == that.canManageCompany &&
               canManageSocialAccounts == that.canManageSocialAccounts &&
               canCreatePosts == that.canCreatePosts &&
               canSchedulePosts == that.canSchedulePosts &&
               canPublishPosts == that.canPublishPosts &&
               canViewAnalytics == that.canViewAnalytics &&
               canManageBots == that.canManageBots &&
               canAccessSettings == that.canAccessSettings &&
               Objects.equals(customPermissions, that.customPermissions);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(canManageUsers, canManageCompany, canManageSocialAccounts,
                           canCreatePosts, canSchedulePosts, canPublishPosts,
                           canViewAnalytics, canManageBots, canAccessSettings,
                           customPermissions);
    }
    
    @Override
    public String toString() {
        return "UserPermissions{" +
               "canManageUsers=" + canManageUsers +
               ", canManageCompany=" + canManageCompany +
               ", canManageSocialAccounts=" + canManageSocialAccounts +
               ", canCreatePosts=" + canCreatePosts +
               ", canSchedulePosts=" + canSchedulePosts +
               ", canPublishPosts=" + canPublishPosts +
               ", canViewAnalytics=" + canViewAnalytics +
               ", canManageBots=" + canManageBots +
               ", canAccessSettings=" + canAccessSettings +
               ", customPermissions=" + customPermissions +
               '}';
    }
    
    /**
     * Builder class for creating UserPermissions instances.
     */
    public static class Builder {
        private boolean canManageUsers = false;
        private boolean canManageCompany = false;
        private boolean canManageSocialAccounts = false;
        private boolean canCreatePosts = false;
        private boolean canSchedulePosts = false;
        private boolean canPublishPosts = false;
        private boolean canViewAnalytics = false;
        private boolean canManageBots = false;
        private boolean canAccessSettings = false;
        private Map<String, Boolean> customPermissions = new HashMap<>();
        
        public Builder canManageUsers(boolean canManageUsers) {
            this.canManageUsers = canManageUsers;
            return this;
        }
        
        public Builder canManageCompany(boolean canManageCompany) {
            this.canManageCompany = canManageCompany;
            return this;
        }
        
        public Builder canManageSocialAccounts(boolean canManageSocialAccounts) {
            this.canManageSocialAccounts = canManageSocialAccounts;
            return this;
        }
        
        public Builder canCreatePosts(boolean canCreatePosts) {
            this.canCreatePosts = canCreatePosts;
            return this;
        }
        
        public Builder canSchedulePosts(boolean canSchedulePosts) {
            this.canSchedulePosts = canSchedulePosts;
            return this;
        }
        
        public Builder canPublishPosts(boolean canPublishPosts) {
            this.canPublishPosts = canPublishPosts;
            return this;
        }
        
        public Builder canViewAnalytics(boolean canViewAnalytics) {
            this.canViewAnalytics = canViewAnalytics;
            return this;
        }
        
        public Builder canManageBots(boolean canManageBots) {
            this.canManageBots = canManageBots;
            return this;
        }
        
        public Builder canAccessSettings(boolean canAccessSettings) {
            this.canAccessSettings = canAccessSettings;
            return this;
        }
        
        public Builder withCustomPermission(String name, boolean value) {
            this.customPermissions.put(name, value);
            return this;
        }
        
        public UserPermissions build() {
            return new UserPermissions(canManageUsers, canManageCompany, canManageSocialAccounts,
                                      canCreatePosts, canSchedulePosts, canPublishPosts,
                                      canViewAnalytics, canManageBots, canAccessSettings,
                                      customPermissions);
        }
    }
}
