package errors

import (
	stderrors "errors"
	"testing"
)

func TestIsInternal(t *testing.T) {
	t.Run("direct InternalError", func(t *testing.T) {
		err := NewInternalError("db down", stderrors.New("conn refused"))
		if !IsInternal(err) {
			t.Fatalf("IsInternal should return true for direct InternalError")
		}
	})

	t.Run("nil is not internal", func(t *testing.T) {
		if IsInternal(nil) {
			t.Fatalf("IsInternal(nil) must be false")
		}
	})

	t.Run("plain error is not internal", func(t *testing.T) {
		if IsInternal(stderrors.New("plain")) {
			t.Fatalf("IsInternal on plain error must be false")
		}
	})

	t.Run("InternalError wrapping NotFoundError matches BOTH — callers must check IsInternal first", func(t *testing.T) {
		// InternalError.Unwrap() returns Cause, so errors.As traverses into it.
		// This is the load-bearing invariant: an InternalError that happens to
		// wrap a business error (e.g. transaction-manager rollback wrapping)
		// must be classified as infra FIRST at system boundaries. Reversing
		// the check order would misreport a genuine 500 as a 404/400.
		wrapped := NewInternalError("rollback failed", NewNotFoundError("record", "abc"))
		if !IsInternal(wrapped) {
			t.Fatalf("IsInternal should match when NotFoundError is wrapped in InternalError")
		}
		if !IsNotFound(wrapped) {
			t.Fatalf("IsNotFound also matches due to Unwrap — documenting the ordering contract")
		}
	})

	t.Run("NotFoundError alone is not internal", func(t *testing.T) {
		if IsInternal(NewNotFoundError("record", "abc")) {
			t.Fatalf("IsInternal should NOT match a bare NotFoundError")
		}
	})
}
