package records

import (
	"database/sql"
	"errors"
	"strings"
	"testing"

	appErrors "github.com/nexuscrm/kernel/pkg/errors"
	metadataFeature "github.com/nexuscrm/metadata"
	"github.com/nexuscrm/permissions"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/models"
)

func newFolderTypeWriteHookTestService(t *testing.T, db *sql.DB, systemPerms map[string]bool) *PersistenceService {
	t.Helper()

	metaRepo := &stubUpsertMetaRepo{schema: reportFolderWriteValidationSchema()}
	metaSvc := metadataFeature.NewMetadataService(metaRepo, nil, nil)
	permRepo := &stubUpsertPermRepo{
		systemPermsByProfile: map[string]map[string]bool{
			constants.ProfileStandardUser: systemPerms,
		},
	}
	permSvc := permissions.NewPermissionService(permRepo, metaSvc, nil)
	permSvc.SetFolderAccess(permissions.NewFolderAccessService(permSvc, db))

	ps := &PersistenceService{
		metadata:            metaSvc,
		permissions:         permSvc,
		writeCanonicalizers: newRecordWriteCanonicalizers(),
		writeValidators:     newRecordWriteValidators(),
	}
	ps.registerBuiltInFolderWriteCanonicalizers()
	ps.registerBuiltInFolderWriteValidators()
	return ps
}

func reportFolderWriteValidationSchema() *models.ObjectMetadata {
	schema := &models.ObjectMetadata{
		ID:           "obj_report_folder",
		APIName:      constants.TableReportFolder,
		Label:        "Report Folder",
		SharingModel: constants.SharingModelFolderSharing,
		AccessPolicy: &models.ObjectAccessPolicy{
			WriteValidation: &models.RecordWriteValidationAccessPolicy{
				Canonicalizers: []models.RecordWriteCanonicalizationPolicy{
					{Phase: string(contract.RecordWriteValidationBeforeCreate), Capability: folderWriteCanonicalizeFolderTypeCapability},
					{Phase: string(contract.RecordWriteValidationBeforeUpdate), Capability: folderWriteCanonicalizeFolderTypeCapability},
					{Phase: string(contract.RecordWriteValidationBeforeRestore), Capability: folderWriteCanonicalizeFolderTypeCapability},
				},
				Validators: []models.RecordWriteValidationPolicy{
					{Phase: string(contract.RecordWriteValidationBeforeCreate), Capability: folderWriteValidateFolderTypeCapability},
					{Phase: string(contract.RecordWriteValidationBeforeUpdate), Capability: folderWriteValidateFolderTypeCapability},
					{Phase: string(contract.RecordWriteValidationBeforeDelete), Capability: folderWriteValidateFolderTypeCapability},
					{Phase: string(contract.RecordWriteValidationBeforeRestore), Capability: folderWriteValidateFolderTypeCapability},
					{Phase: string(contract.RecordWriteValidationBeforePurge), Capability: folderWriteValidateFolderTypeCapability},
				},
			},
		},
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, Createable: false, Updateable: false},
			{APIName: constants.FieldType, Type: constants.FieldTypeString, Createable: true, Updateable: true},
			{APIName: constants.FieldIsDeleted, Type: constants.FieldTypeBoolean, Createable: false, Updateable: false},
		},
	}
	makeFieldsMap(schema)
	return schema
}

func assertFolderTypeForbidden(t *testing.T, err error, wantMessage string) {
	t.Helper()
	if err == nil {
		t.Fatalf("error = nil, want ForbiddenError containing %q", wantMessage)
	}
	var forbidden *appErrors.ForbiddenError
	if !errors.As(err, &forbidden) {
		t.Fatalf("error type = %T (%v), want *ForbiddenError", err, err)
	}
	if !strings.Contains(forbidden.Message, wantMessage) {
		t.Fatalf("ForbiddenError message = %q, want to contain %q", forbidden.Message, wantMessage)
	}
}
