package permissions

import (
	"context"

	"github.com/nexuscrm/kernel/pkg/errors"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

// objectPermissionsObjectTypePhysicalColumn is the legacy storage column
// shared by object- and field-permission rows. New lifecycle code keeps the
// compatibility spelling behind this permissions-module boundary.
const objectPermissionsObjectTypePhysicalColumn = "SobjectType"

func validateObjectPermissionGrantDependencies(
	object string,
	read bool,
	create bool,
	edit bool,
	deletePermission bool,
	viewAllRecords bool,
	modifyAllRecords bool,
) error {
	return ValidateObjectPermissionDependencies(models.ObjectPermissions{
		SobjectType:                 object,
		PermissionsRead:             read,
		PermissionsCreate:           create,
		PermissionsEdit:             edit,
		PermissionsDelete:           deletePermission,
		PermissionsViewAllRecords:   viewAllRecords,
		PermissionsModifyAllRecords: modifyAllRecords,
	})
}

// --- Permission Set Permissions ---

// GetPermissionSetObjectPermissions retrieves all object permissions for a permission set
func (ps *PermissionService) GetPermissionSetObjectPermissions(ctx context.Context, permissionSetID string) ([]models.ObjectPermissions, error) {
	return ps.repo.ListPermissionSetObjectPermissions(ctx, permissionSetID)
}

// GetPermissionSetFieldPermissions retrieves all field permissions for a permission set
func (ps *PermissionService) GetPermissionSetFieldPermissions(ctx context.Context, permissionSetID string) ([]models.FieldPermissions, error) {
	return ps.repo.ListPermissionSetFieldPermissions(ctx, permissionSetID)
}

// UpdatePermissionSetObjectPermission creates or updates an object permission for a permission set
func (ps *PermissionService) UpdatePermissionSetObjectPermission(ctx context.Context, perm models.ObjectPermissions) error {
	if perm.ParentID == "" {
		return errors.NewValidationError("permission_set_id", "permission_set_id is required")
	}

	// Validate permission dependencies before persisting
	if err := ValidateObjectPermissionDependencies(perm); err != nil {
		return errors.NewValidationError("", err.Error())
	}

	// Parent-controlled authoring guard (F3): mirror F1/F2 on the permission-set
	// authoring surface. Empty-ParentID error above runs first and is preserved.
	if err := ps.RejectParentControlledChildWrite(ctx, perm.SobjectType); err != nil {
		return err
	}

	if err := ps.repo.UpsertObjectPermission(ctx, perm); err != nil {
		return err
	}
	ps.InvalidateCache()
	return nil
}

// UpdatePermissionSetFieldPermission creates or updates a field permission for a permission set
func (ps *PermissionService) UpdatePermissionSetFieldPermission(ctx context.Context, perm models.FieldPermissions) error {
	if perm.ParentID == "" {
		return errors.NewValidationError("permission_set_id", "permission_set_id is required")
	}
	if err := ValidateFieldPermissionDependencies(perm); err != nil {
		return errors.NewValidationError(constants.FieldFieldPermissions_PermissionsEdit, err.Error())
	}
	if err := ps.repo.UpsertFieldPermission(ctx, perm); err != nil {
		return err
	}
	ps.InvalidateCache()
	return nil
}

// --- Effective Permissions (Admin View) ---

// GetEffectiveObjectPermissions returns the merged object permissions for a specific user
func (ps *PermissionService) GetEffectiveObjectPermissions(ctx context.Context, userID string) ([]models.ObjectPermissions, error) {
	profileID, err := ps.repo.GetUserProfileID(ctx, userID)
	if err != nil {
		return nil, errors.NewInternalError("failed to get user profile", err)
	}

	return ps.ListEffectiveObjectPermissionsForUser(ctx, userID, profileID)
}

// GetEffectiveFieldPermissions returns the merged field permissions for a specific user
func (ps *PermissionService) GetEffectiveFieldPermissions(ctx context.Context, userID string) ([]models.FieldPermissions, error) {
	profileID, err := ps.repo.GetUserProfileID(ctx, userID)
	if err != nil {
		return nil, errors.NewInternalError("failed to get user profile", err)
	}

	return ps.ListEffectiveFieldPermissionsForUser(ctx, userID, profileID)
}

// --- Permission Set Management ---

// CreatePermissionSet creates a new permission set
func (ps *PermissionService) CreatePermissionSet(ctx context.Context, name, label, description string) (string, error) {
	return ps.repo.CreatePermissionSet(ctx, name, label, description)
}

// UpdatePermissionSet updates a permission set
func (ps *PermissionService) UpdatePermissionSet(ctx context.Context, id string, name, label, description string) error {
	return ps.repo.UpdatePermissionSet(ctx, id, name, label, description)
}

// DeletePermissionSet deletes a permission set
func (ps *PermissionService) DeletePermissionSet(ctx context.Context, id string) error {
	return ps.repo.DeletePermissionSet(ctx, id)
}
