package auth

import (
	"fmt"
	"strings"
)

// Permission constants for type safety
const (
	// Job permissions
	PermissionJobsCreate = "jobs:create"
	PermissionJobsRead   = "jobs:read"
	PermissionJobsUpdate = "jobs:update"
	PermissionJobsDelete = "jobs:delete"

	// Data permissions
	PermissionDataCreate = "data:create"
	PermissionDataRead   = "data:read"
	PermissionDataUpdate = "data:update"
	PermissionDataDelete = "data:delete"

	// Model permissions
	PermissionModelsCreate = "models:create"
	PermissionModelsRead   = "models:read"
	PermissionModelsUpdate = "models:update"
	PermissionModelsDelete = "models:delete"

	// System permissions
	PermissionSystemConfig  = "system:config"
	PermissionSystemMetrics = "system:metrics"
	PermissionSystemLogs    = "system:logs"
	PermissionSystemUsers   = "system:users"

	// Wildcard permission
	PermissionAll = "*"
)

// Role constants
const (
	RoleAdmin         = "admin"
	RoleDataScientist = "data_scientist"
	RoleDataEngineer  = "data_engineer"
	RoleViewer        = "viewer"
	RoleOperator      = "operator"
)

// PermissionGroup represents a group of related permissions
type PermissionGroup struct {
	Name        string
	Description string
	Permissions []string
}

// PermissionGroups defines built-in permission groups.
var PermissionGroups = map[string]PermissionGroup{
	"full_access": {
		Name:        "Full Access",
		Permissions: []string{PermissionAll},
		Description: "Complete system access",
	},
	"job_management": {
		Name: "Job Management",
		Permissions: []string{
			PermissionJobsCreate,
			PermissionJobsRead,
			PermissionJobsUpdate,
			PermissionJobsDelete,
		},
		Description: "Create, read, update, and delete ML jobs",
	},
	"data_access": {
		Name: "Data Access",
		Permissions: []string{
			PermissionDataRead,
			PermissionDataCreate,
			PermissionDataUpdate,
			PermissionDataDelete,
		},
		Description: "Access and manage datasets",
	},
	"readonly": {
		Name: "Read Only",
		Permissions: []string{
			PermissionJobsRead,
			PermissionDataRead,
			PermissionModelsRead,
			PermissionSystemMetrics,
		},
		Description: "View-only access to system resources",
	},
	"system_admin": {
		Name: "System Administration",
		Permissions: []string{
			PermissionSystemConfig,
			PermissionSystemLogs,
			PermissionSystemUsers,
			PermissionSystemMetrics,
		},
		Description: "System configuration and user management",
	},
}

// GetPermissionGroup returns a permission group by name
func GetPermissionGroup(name string) (PermissionGroup, bool) {
	group, exists := PermissionGroups[name]
	return group, exists
}

// ValidatePermission checks if a permission string is valid
func ValidatePermission(permission string) error {
	if permission == PermissionAll {
		return nil
	}

	// Check if permission matches known patterns
	validPrefixes := []string{"jobs:", "data:", "models:", "system:"}
	for _, prefix := range validPrefixes {
		if strings.HasPrefix(permission, prefix) {
			return nil
		}
	}

	return fmt.Errorf("invalid permission format: %s", permission)
}

// ValidateRole checks if a role is valid
func ValidateRole(role string) error {
	validRoles := []string{RoleAdmin, RoleDataScientist, RoleDataEngineer, RoleViewer, RoleOperator}
	for _, validRole := range validRoles {
		if role == validRole {
			return nil
		}
	}
	return fmt.Errorf("invalid role: %s", role)
}

// ExpandPermissionGroups converts permission group names to actual permissions
func ExpandPermissionGroups(groups []string) ([]string, error) {
	var permissions []string

	for _, groupName := range groups {
		if groupName == PermissionAll {
			return []string{PermissionAll}, nil
		}

		group, exists := GetPermissionGroup(groupName)
		if !exists {
			return nil, fmt.Errorf("unknown permission group: %s", groupName)
		}

		permissions = append(permissions, group.Permissions...)
	}

	// Remove duplicates
	unique := make(map[string]bool)
	for _, perm := range permissions {
		unique[perm] = true
	}

	result := make([]string, 0, len(unique))
	for perm := range unique {
		result = append(result, perm)
	}

	return result, nil
}

// PermissionCheckResult represents the result of a permission check
type PermissionCheckResult struct {
	Permission string   `json:"permission"`
	User       string   `json:"user"`
	Roles      []string `json:"roles"`
	Missing    []string `json:"missing,omitempty"`
	Allowed    bool     `json:"allowed"`
}

// CheckMultiplePermissions checks multiple permissions at once
func (u *User) CheckMultiplePermissions(permissions []string) []PermissionCheckResult {
	results := make([]PermissionCheckResult, len(permissions))

	for i, permission := range permissions {
		allowed := u.HasPermission(permission)
		missing := []string{}
		if !allowed {
			missing = []string{permission}
		}

		results[i] = PermissionCheckResult{
			Allowed:    allowed,
			Permission: permission,
			User:       u.Name,
			Roles:      u.Roles,
			Missing:    missing,
		}
	}

	return results
}

// GetEffectivePermissions returns all effective permissions for a user
func (u *User) GetEffectivePermissions() []string {
	if u.Permissions[PermissionAll] {
		return []string{PermissionAll}
	}

	permissions := make([]string, 0, len(u.Permissions))
	for perm := range u.Permissions {
		permissions = append(permissions, perm)
	}

	return permissions
}
