package com.saas.admin.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;

/**
 * Permission entity for RBAC (Role-Based Access Control)
 * 
 * Permissions define granular actions that can be performed on resources.
 * Format: resource:action
 * 
 * Examples:
 * - "tenant:read", "tenant:write", "tenant:delete"
 * - "user:read", "user:write", "user:delete"
 * - "voip:read", "voip:write", "voip:delete"
 * - "cost:read", "call:read"
 * 
 * Permissions are assigned to roles, and roles are assigned to users.
 */
@Entity
@Table(name = "permissions", schema = "saas_db",
       uniqueConstraints = @UniqueConstraint(columnNames = {"resource", "action"}))
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Permission {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    /**
     * Resource name (e.g., "tenant", "user", "voip", "cost", "call")
     * Lowercase, singular form
     */
    @Column(nullable = false, length = 50)
    private String resource;
    
    /**
     * Action that can be performed (e.g., "read", "write", "delete", "manage")
     * Standard CRUD: read, write, delete
     * Special: manage (full control), execute (for actions)
     */
    @Column(nullable = false, length = 50)
    private String action;
    
    /**
     * Human-readable permission description
     */
    @Column(length = 500)
    private String description;
    
    /**
     * Whether this permission is active and can be used
     */
    @Column(nullable = false)
    @Builder.Default
    private Boolean isActive = true;
    
    /**
     * Whether this is a system permission (cannot be deleted)
     */
    @Column(nullable = false)
    @Builder.Default
    private Boolean isSystem = false;
    
    /**
     * Roles that have this permission
     * Many-to-many relationship via role_permissions junction table
     */
    @OneToMany(mappedBy = "permission", cascade = CascadeType.ALL, orphanRemoval = true)
    @Builder.Default
    private Set<RolePermission> rolePermissions = new HashSet<>();
    
    @CreationTimestamp
    @Column(nullable = false, updatable = false)
    private LocalDateTime createdAt;
    
    /**
     * Get permission string in format "resource:action"
     * Used in Spring Security @PreAuthorize annotations
     * 
     * Example: "tenant:read", "voip:write"
     */
    public String getPermissionString() {
        return resource + ":" + action;
    }
    
    /**
     * Parse permission string into resource and action
     * Format: "resource:action"
     */
    public static Permission fromString(String permissionString, String description) {
        String[] parts = permissionString.split(":");
        if (parts.length != 2) {
            throw new IllegalArgumentException("Invalid permission format. Expected 'resource:action', got: " + permissionString);
        }
        
        return Permission.builder()
                .resource(parts[0].toLowerCase())
                .action(parts[1].toLowerCase())
                .description(description)
                .isActive(true)
                .isSystem(false)
                .build();
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Permission)) return false;
        Permission that = (Permission) o;
        return resource.equals(that.resource) && action.equals(that.action);
    }
    
    @Override
    public int hashCode() {
        return java.util.Objects.hash(resource, action);
    }
}
