package contract

import (
	"context"

	"github.com/nexuscrm/shared/pkg/models"
)

// PermissionAdmin is the neutral permission administration surface used by API
// dialects. The permission engine owns catalog reads, effective permission
// projection, mutation transactions, row locks, and cache invalidation. Dialects
// own only request parsing and wire envelopes.
type PermissionAdmin interface {
	ListObjectPermissions(ctx context.Context, user *models.UserSession) ([]ObjectAccessProjection, error)
	ListSystemPermissionCatalog(ctx context.Context) ([]CapabilityCatalogEntry, error)
	GetPermissionSetSystemGrants(ctx context.Context, permSetID string) (map[string]bool, error)
	SavePermissionSetSystemGrants(ctx context.Context, permSetID string, grants map[string]bool, actor *models.UserSession) error
	EffectivePermissions(ctx context.Context, viewer *models.UserSession, targetUserID string) (*EffectivePermissionsResult, error)

	ListRecordTypeCatalog(ctx context.Context) ([]PermissionRecordTypeCatalogEntry, error)
	GetPermissionSetRecordTypeGrants(ctx context.Context, permSetID string) ([]RecordTypeVisibilityGrant, error)
	SavePermissionSetRecordTypeGrants(ctx context.Context, permSetID string, grants map[string]PermissionRecordTypeGrantChange) error

	ListCustomPermissionCatalog(ctx context.Context) ([]CustomCapabilityCatalogEntry, error)
	GetPermissionSetCustomPermissionGrants(ctx context.Context, permSetID string) ([]CustomCapabilityGrant, error)
	SavePermissionSetCustomPermissionGrants(ctx context.Context, permSetID string, grants map[string]bool) error
}

// ObjectAccessProjection is the neutral, dialect-independent shape of a single
// object's effective CRUD/administrative access. It is the contract-boundary
// projection of the engine's object-permission row: no SF field names, no JSON
// tags. The SF dialect re-derives its own wire keys from these neutral fields
// in its wire builder.
type ObjectAccessProjection struct {
	ResourceType  string
	CanRead       bool
	CanCreate     bool
	CanEdit       bool
	CanDelete     bool
	CanDeactivate bool
	CanViewAll    bool
	CanModifyAll  bool
}

// FieldAccessProjection is the neutral shape of a single field's effective
// read/edit access and create-time field capability. FieldName is the RAW field component (unqualified); the
// dialect is responsible for any object-qualification of the field name.
type FieldAccessProjection struct {
	CanCreate    bool
	ResourceType string
	FieldName    string
	CanRead      bool
	CanEdit      bool
}

// ApplicationAccessProjection is the neutral shape of a subject-effective
// application visibility decision. Application presentation and public wire
// semantics remain owned by the consuming L1 AppMetadata projection.
type ApplicationAccessProjection struct {
	ApplicationID string
	CanView       bool
	IsDefault     bool
}

// NavigationAccessProjection is the neutral shape of a subject-effective
// navigation-key visibility decision.
type NavigationAccessProjection struct {
	NavigationKey string
	CanView       bool
}

// CapabilityCatalogEntry is the neutral shape of one system-permission catalog
// entry. RequiresCapability replaces the engine's *string RequiresPermission and
// is empty when there is no prerequisite (nil deref -> "").
type CapabilityCatalogEntry struct {
	APIName            string
	Label              string
	Category           string
	Description        string
	RequiresCapability string
}

// RecordTypeVisibilityGrant is the neutral shape of one record-type visibility
// grant on a permission set.
type RecordTypeVisibilityGrant struct {
	RecordTypeID string
	IsVisible    bool
}

// CustomCapabilityCatalogEntry is the neutral shape of one custom-permission
// catalog entry.
type CustomCapabilityCatalogEntry struct {
	ID      string
	APIName string
	Label   string
}

// CustomCapabilityGrant is the neutral shape of one custom-permission grant on a
// permission set. CapabilityID replaces the engine's CustomPermissionID.
type CustomCapabilityGrant struct {
	CapabilityID string
}

type PermissionRecordTypeCatalogEntry struct {
	RecordTypeID  string
	ObjectAPIName string
	Name          string
	Label         string
	IsActive      bool
	IsMaster      bool
}

type PermissionRecordTypeGrantChange struct {
	IsVisible bool
}

type EffectivePermissionsResult struct {
	SystemPermissions      map[string]bool
	CustomPermissions      map[string]bool
	ObjectPermissions      []ObjectAccessProjection
	FieldPermissions       []FieldAccessProjection
	ApplicationPermissions []ApplicationAccessProjection
	NavigationPermissions  []NavigationAccessProjection
	// RecordTypePermissions contains only stable record-type IDs and effective
	// visibility facts. Catalog supplies names and AppInstallation scope from
	// the same immutable serving revision.
	RecordTypePermissions map[string]bool
}

// EffectiveActionPermissions contains only the caller-effective permission
// facts consumed by Catalog action preparation. Object-operation guards remain
// owned by the PermissionService decision interface because metadata policy is
// part of those decisions. This deliberately is not an abbreviated
// EffectivePermissionsResult: callers must not reinterpret it as a complete
// permission export.
type EffectiveActionPermissions struct {
	SystemPermissions map[string]bool
	CustomPermissions map[string]bool
}

type PermissionAdminErrorKind string

const (
	PermissionAdminErrorServer            PermissionAdminErrorKind = "server"
	PermissionAdminErrorSanitizedInternal PermissionAdminErrorKind = "sanitized_internal"
	PermissionAdminErrorNotFound          PermissionAdminErrorKind = "not_found"
	PermissionAdminErrorForbidden         PermissionAdminErrorKind = "forbidden"
	PermissionAdminErrorInvalidField      PermissionAdminErrorKind = "invalid_field"
)

// PermissionAdminError carries the old permission-admin route classifications
// across the neutral seam without exposing backend error types to the L1 module.
type PermissionAdminError struct {
	Kind    PermissionAdminErrorKind
	Message string
}

func (e *PermissionAdminError) Error() string {
	if e == nil {
		return ""
	}
	return e.Message
}
