package db_test

import (
	"context"
	"errors"
	"log/slog"
	"strings"
	"testing"

	"github.com/owncord/server/db"
)

// fakeAuditor lets a test drive WriteAudit down either the success or the
// failure path without a real database.
type fakeAuditor struct {
	err    error
	called bool
}

func (f *fakeAuditor) LogAudit(_ context.Context, _ int64, _, _ string, _ int64, _ string) error {
	f.called = true
	return f.err
}

// captureLogs redirects the default slog logger to a buffer for the duration
// of fn and returns everything it wrote.
func captureLogs(t *testing.T, fn func()) string {
	t.Helper()
	var buf strings.Builder
	prev := slog.Default()
	slog.SetDefault(slog.New(slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelDebug})))
	defer slog.SetDefault(prev)
	fn()
	return buf.String()
}

func TestWriteAudit_LogsFailureButDoesNotPropagate(t *testing.T) {
	a := &fakeAuditor{err: errors.New("disk on fire")}

	// WriteAudit returns nothing, so "never propagated" is structural — the
	// call simply must not panic and must record the failure.
	out := captureLogs(t, func() {
		db.WriteAudit(context.Background(), a, 7, "user_ban", "user", 42, "spam")
	})

	if !a.called {
		t.Fatal("WriteAudit did not attempt the underlying LogAudit")
	}
	for _, want := range []string{
		"audit log write failed",
		"action=user_ban",
		"actor_id=7",
		"target_type=user",
		"target_id=42",
		"disk on fire",
	} {
		if !strings.Contains(out, want) {
			t.Errorf("failure log missing %q; got: %s", want, out)
		}
	}
	// The detail string must not leak into logs.
	if strings.Contains(out, "spam") {
		t.Errorf("detail string leaked into audit failure log: %s", out)
	}
}

func TestWriteAudit_SuccessLogsNothing(t *testing.T) {
	a := &fakeAuditor{err: nil}

	out := captureLogs(t, func() {
		db.WriteAudit(context.Background(), a, 1, "user_login", "user", 1, "")
	})

	if !a.called {
		t.Fatal("WriteAudit did not attempt the underlying LogAudit")
	}
	if strings.Contains(out, "audit log write failed") {
		t.Errorf("successful audit write should not log a failure; got: %s", out)
	}
}
