package bootstrap

import (
	"baron-sso-backend/internal/domain"
	"context"
	"errors"
	"testing"
)

func TestEnsureSuperAdminCreatesIdentityLocalUserAndKetoRelation(t *testing.T) {
	ctx := context.Background()
	identityAdmin := &fakeSuperAdminIdentityAdmin{createdID: "identity-1"}
	store := &fakeSuperAdminStore{}

	result, err := EnsureSuperAdmin(ctx, identityAdmin, store, EnsureSuperAdminOptions{
		Email:    "new-admin@example.com",
		Password: "Password!123",
		Name:     "New Admin",
		Source:   "test",
	})
	if err != nil {
		t.Fatalf("EnsureSuperAdmin returned error: %v", err)
	}
	if !result.IdentityCreated {
		t.Fatal("identity must be created")
	}
	if !result.LocalUserCreated {
		t.Fatal("local user must be created")
	}
	if result.IdentityID != "identity-1" {
		t.Fatalf("identity ID = %q, want identity-1", result.IdentityID)
	}
	if store.user == nil {
		t.Fatal("local user was not stored")
	}
	if store.user.Email != "new-admin@example.com" {
		t.Fatalf("local user email = %q", store.user.Email)
	}
	if store.user.Role != domain.RoleSuperAdmin {
		t.Fatalf("local user role = %q, want %q", store.user.Role, domain.RoleSuperAdmin)
	}
	if len(store.ketoSubjects) != 1 || store.ketoSubjects[0] != "User:identity-1" {
		t.Fatalf("keto subjects = %#v, want User:identity-1", store.ketoSubjects)
	}
	if identityAdmin.createdUser == nil || identityAdmin.createdUser.Attributes["role"] != domain.RoleSuperAdmin {
		t.Fatalf("created identity attributes = %#v", identityAdmin.createdUser)
	}
}

func TestEnsureSuperAdminPromotesExistingLocalUser(t *testing.T) {
	ctx := context.Background()
	identityAdmin := &fakeSuperAdminIdentityAdmin{existingID: "identity-1"}
	store := &fakeSuperAdminStore{
		user: &domain.User{
			ID:     "local-user-1",
			Email:  "existing@example.com",
			Name:   "Existing",
			Role:   domain.RoleUser,
			Status: domain.UserStatusPreboarding,
		},
	}

	result, err := EnsureSuperAdmin(ctx, identityAdmin, store, EnsureSuperAdminOptions{
		Email:    "existing@example.com",
		Password: "Password!123",
		Name:     "Existing Admin",
		Source:   "test",
	})
	if err != nil {
		t.Fatalf("EnsureSuperAdmin returned error: %v", err)
	}
	if result.IdentityCreated {
		t.Fatal("existing identity must not be recreated")
	}
	if !result.LocalUserUpdated {
		t.Fatal("local user must be promoted")
	}
	if store.user.Role != domain.RoleSuperAdmin {
		t.Fatalf("local user role = %q, want %q", store.user.Role, domain.RoleSuperAdmin)
	}
	if store.user.Status != domain.UserStatusActive {
		t.Fatalf("local user status = %q, want %q", store.user.Status, domain.UserStatusActive)
	}
	if len(store.ketoSubjects) != 1 || store.ketoSubjects[0] != "User:local-user-1" {
		t.Fatalf("keto subjects = %#v, want User:local-user-1", store.ketoSubjects)
	}
}

func TestEnsureSuperAdminRequiresPasswordForNewIdentity(t *testing.T) {
	_, err := EnsureSuperAdmin(context.Background(), &fakeSuperAdminIdentityAdmin{}, &fakeSuperAdminStore{}, EnsureSuperAdminOptions{
		Email: "new-admin@example.com",
		Name:  "New Admin",
	})

	if err == nil {
		t.Fatal("expected error")
	}
}

type fakeSuperAdminIdentityAdmin struct {
	existingID    string
	createdID     string
	createdUser   *domain.BrokerUser
	createdSecret string
}

func (f *fakeSuperAdminIdentityAdmin) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
	return f.existingID, nil
}

func (f *fakeSuperAdminIdentityAdmin) CreateUser(ctx context.Context, user *domain.BrokerUser, password string) (string, error) {
	if f.createdID == "" {
		return "", errors.New("created id is not configured")
	}
	f.createdUser = user
	f.createdSecret = password
	return f.createdID, nil
}

func (f *fakeSuperAdminIdentityAdmin) UpdateIdentityPassword(ctx context.Context, identityID string, newPassword string) error {
	return nil
}

type fakeSuperAdminStore struct {
	user         *domain.User
	ketoSubjects []string
}

func (f *fakeSuperAdminStore) FindUserByEmail(ctx context.Context, email string) (*domain.User, error) {
	if f.user == nil {
		return nil, nil
	}
	return f.user, nil
}

func (f *fakeSuperAdminStore) CreateUser(ctx context.Context, user *domain.User) error {
	copied := *user
	f.user = &copied
	return nil
}

func (f *fakeSuperAdminStore) UpdateUserSuperAdmin(ctx context.Context, userID string, name string) (*domain.User, error) {
	if f.user == nil {
		return nil, errors.New("user not found")
	}
	f.user.Role = domain.RoleSuperAdmin
	f.user.Status = domain.UserStatusActive
	if name != "" {
		f.user.Name = name
	}
	return f.user, nil
}

func (f *fakeSuperAdminStore) EnqueueSuperAdminRelation(ctx context.Context, userID string) error {
	f.ketoSubjects = append(f.ketoSubjects, "User:"+userID)
	return nil
}
