package identity

import (
	"errors"
	"sort"
	"time"
)

var (
	ErrNotFound    = errors.New("identity not found")
	ErrUnavailable = errors.New("identity service unavailable")
)

type Kind string

const (
	KindAdmin  Kind = "admin"
	KindPortal Kind = "portal"
)

type Account struct {
	ID                  string
	Kind                Kind
	Login               string
	DisplayName         string
	Role                string
	Permissions         []string
	PasswordHash        string
	AuthSource          string
	Active              bool
	FailedLogins        int
	LockedUntil         *time.Time
	TOTPEnabled         bool
	EncryptedTOTPSecret []byte
	TOTPKekVersion      *int
	TOTPLastStep        *int64
	TOTPBackupCodes     []byte
	DepartmentID        *string
	DepartmentName      string
	CreatedAt           time.Time
	UpdatedAt           time.Time
}

const (
	PermissionIdentityManage        = "identity:manage"
	PermissionProviderRead          = "provider:read"
	PermissionProviderManage        = "provider:manage"
	PermissionAPIKeyRead            = "api_key:read"
	PermissionAPIKeyManage          = "api_key:manage"
	PermissionAuditRead             = "audit:read"
	PermissionUsageRead             = "usage:read"
	PermissionOutboxRead            = "outbox:read"
	PermissionOutboxManage          = "outbox:manage"
	PermissionContentPolicyRead     = "content_policy:read"
	PermissionContentPolicyManage   = "content_policy:manage"
	PermissionPricingRead           = "pricing:read"
	PermissionPricingManage         = "pricing:manage"
	PermissionPromptRead            = "prompt:read"
	PermissionPromptManage          = "prompt:manage"
	PermissionKnowledgeRead         = "knowledge:read"
	PermissionKnowledgeManage       = "knowledge:manage"
	PermissionToolRead              = "tool:read"
	PermissionToolManage            = "tool:manage"
	PermissionApplicationRead       = "application:read"
	PermissionApplicationManage     = "application:manage"
	PermissionNotificationRead      = "notification:read"
	PermissionNotificationManage    = "notification:manage"
	PermissionMCPServerRead         = "mcp_server:read"
	PermissionMCPServerManage       = "mcp_server:manage"
	PermissionSkillRead             = "skill:read"
	PermissionSkillManage           = "skill:manage"
	PermissionDigitalEmployeeRead   = "digital_employee:read"
	PermissionDigitalEmployeeManage = "digital_employee:manage"
	PermissionMarketplaceRead       = "marketplace:read"
	PermissionMarketplaceManage     = "marketplace:manage"
	PermissionFileRead              = "file:read"
	PermissionFileManage            = "file:manage"
)

var rolePermissions = map[string][]string{
	"superadmin": {"*"},
	"operator": {
		PermissionProviderRead, PermissionProviderManage,
		PermissionAPIKeyRead, PermissionAPIKeyManage,
		PermissionUsageRead,
		PermissionOutboxRead, PermissionOutboxManage,
		PermissionContentPolicyRead, PermissionContentPolicyManage,
		PermissionPricingRead, PermissionPricingManage,
		PermissionPromptRead, PermissionPromptManage,
		PermissionKnowledgeRead, PermissionKnowledgeManage,
		PermissionToolRead, PermissionToolManage,
		PermissionApplicationRead, PermissionApplicationManage,
		PermissionNotificationRead, PermissionNotificationManage,
		PermissionMCPServerRead, PermissionMCPServerManage,
		PermissionSkillRead, PermissionSkillManage,
		PermissionDigitalEmployeeRead, PermissionDigitalEmployeeManage,
		PermissionMarketplaceRead, PermissionMarketplaceManage,
		PermissionFileRead, PermissionFileManage,
	},
	"auditor": {PermissionProviderRead, PermissionAPIKeyRead, PermissionAuditRead, PermissionUsageRead, PermissionOutboxRead, PermissionContentPolicyRead, PermissionPricingRead, PermissionPromptRead, PermissionKnowledgeRead, PermissionToolRead, PermissionApplicationRead, PermissionNotificationRead, PermissionMCPServerRead, PermissionSkillRead, PermissionDigitalEmployeeRead, PermissionMarketplaceRead, PermissionFileRead},
	"member":  {},
}

func EffectivePermissions(account Account) []string {
	seen := make(map[string]struct{})
	result := make([]string, 0, len(account.Permissions)+4)
	for _, permissions := range [][]string{rolePermissions[account.Role], account.Permissions} {
		for _, permission := range permissions {
			if _, exists := seen[permission]; exists {
				continue
			}
			seen[permission] = struct{}{}
			result = append(result, permission)
		}
	}
	sort.Strings(result)
	return result
}

func HasPermission(account Account, required string) bool {
	for _, permission := range EffectivePermissions(account) {
		if permission == "*" || permission == required {
			return true
		}
	}
	return false
}

func (a Account) Locked(now time.Time) bool {
	return a.LockedUntil != nil && a.LockedUntil.After(now)
}
