package setupcmd

import (
	"bytes"
	"context"
	"errors"
	"strings"
	"testing"

	"github.com/nexuscrm/persistence"
)

type permissionStateInitializationFake struct {
	state persistence.PermissionState
	err   error
	calls int
}

func (fake *permissionStateInitializationFake) EnsureInitialized(context.Context) (persistence.PermissionState, error) {
	fake.calls++
	return fake.state, fake.err
}

func TestRunPermissionStateInitializationCommandEnsuresAndReportsState(t *testing.T) {
	initializer := &permissionStateInitializationFake{state: persistence.PermissionState{
		Version:         permissionStateActivationVersionForTest(t, 1),
		EnforcementMode: persistence.PermissionStateDarkMode,
	}}
	var stdout, stderr bytes.Buffer
	code := runPermissionStateInitializationCommand(
		context.Background(),
		nil,
		&stdout,
		&stderr,
		func() (permissionStateInitializer, error) { return initializer, nil },
	)
	if code != 0 {
		t.Fatalf("exit = %d, stderr = %q", code, stderr.String())
	}
	if initializer.calls != 1 {
		t.Fatalf("initialization calls = %d, want 1", initializer.calls)
	}
	if want := "{\"revision\":1,\"enforcementMode\":\"dark\"}\n"; stdout.String() != want {
		t.Fatalf("stdout = %q, want %q", stdout.String(), want)
	}
	if stderr.Len() != 0 {
		t.Fatalf("stderr = %q, want empty", stderr.String())
	}
}

func TestRunPermissionStateInitializationCommandFailsClosed(t *testing.T) {
	t.Run("arguments before repository", func(t *testing.T) {
		called := false
		var stdout, stderr bytes.Buffer
		code := runPermissionStateInitializationCommand(
			context.Background(),
			[]string{"unexpected"},
			&stdout,
			&stderr,
			func() (permissionStateInitializer, error) {
				called = true
				return nil, nil
			},
		)
		if code != 2 || called || stdout.Len() != 0 || !strings.Contains(stderr.String(), "unexpected arguments") {
			t.Fatalf("argument failure = code %d, factory %t, stdout %q, stderr %q", code, called, stdout.String(), stderr.String())
		}
	})
	t.Run("repository", func(t *testing.T) {
		var stdout, stderr bytes.Buffer
		code := runPermissionStateInitializationCommand(
			context.Background(), nil, &stdout, &stderr,
			func() (permissionStateInitializer, error) { return nil, errors.New("unavailable") },
		)
		if code != 1 || stdout.Len() != 0 || !strings.Contains(stderr.String(), "open repository") {
			t.Fatalf("repository failure = code %d, stdout %q, stderr %q", code, stdout.String(), stderr.String())
		}
	})
	t.Run("initialization", func(t *testing.T) {
		var stdout, stderr bytes.Buffer
		code := runPermissionStateInitializationCommand(
			context.Background(), nil, &stdout, &stderr,
			func() (permissionStateInitializer, error) {
				return &permissionStateInitializationFake{err: errors.New("conflict")}, nil
			},
		)
		if code != 1 || stdout.Len() != 0 || !strings.Contains(stderr.String(), "initialize permission state") {
			t.Fatalf("initialization failure = code %d, stdout %q, stderr %q", code, stdout.String(), stderr.String())
		}
	})
}
