package apperror

import (
	"errors"
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestWrapPreservesCauseWithoutChangingClientMessage(t *testing.T) {
	cause := errors.New("database connection details")
	err := Wrap(cause, CodeNotFound, http.StatusNotFound, "User not found")

	require.ErrorIs(t, err, cause)
	require.Equal(t, "User not found", err.ClientMessage())
	require.Contains(t, err.Error(), "database connection details")
}

func TestErrorsMatchByCode(t *testing.T) {
	err := Wrap(errors.New("database connection details"), CodeAlreadyInUse, http.StatusBadRequest, "email is already in use")
	wrapped := Wrap(err, CodeInternal, http.StatusInternalServerError, "request failed")

	require.True(t, IsCode(err, CodeAlreadyInUse))
	require.True(t, IsCode(wrapped, CodeAlreadyInUse))
	require.ErrorIs(t, err, New(CodeAlreadyInUse, http.StatusBadRequest, "username is already in use"))
	require.NotErrorIs(t, err, errors.Join(New(CodeAlreadyInUse, http.StatusBadRequest, "username is already in use")))
	require.False(t, IsCode(wrapped, CodeNotFound))
}

func TestErrorCopiesFields(t *testing.T) {
	fields := []FieldError{{Field: "email", Code: "required", Message: "is required"}}
	err := New(CodeValidationFailed, http.StatusBadRequest, "Request validation failed").WithFields(fields)
	fields[0].Message = "changed"

	require.Equal(t, "is required", err.Fields()[0].Message)
}

func TestErrorCopiesDetails(t *testing.T) {
	err := New(CodeAlreadyInUse, http.StatusBadRequest, "Already in use").WithDetail("property", "email")
	details := err.Details()
	details["property"] = "password"

	require.Equal(t, map[string]string{"property": "email"}, err.Details())
}
