/*
 * Copyright 2022 CloudWeGo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nphttp2

import (
	"errors"
	"testing"

	"github.com/cloudwego/kitex/internal/test"
	"github.com/cloudwego/kitex/pkg/kerrors"
	"github.com/cloudwego/kitex/pkg/remote"
	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/codes"
	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status"
)

var _ error = (*mockError)(nil)

type mockError struct{}

func (m mockError) Error() string {
	return "mock"
}

func TestConvertStatus(t *testing.T) {
	t.Run("nil", func(t *testing.T) {
		test.Assert(t, convertStatus(nil).Code() == codes.OK)
	})

	t.Run("Biz-GRPCStatusError", func(t *testing.T) {
		err := kerrors.ErrBiz.WithCause(status.Err(100, "mock"))
		test.Assert(t, convertStatus(err).Code() == 100)
	})

	t.Run("Biz-TransError", func(t *testing.T) {
		transErr := remote.NewTransError(101, errors.New("mock_trans_err"))
		err := kerrors.ErrBiz.WithCause(transErr)
		test.Assert(t, convertStatus(err).Code() == 101)
	})

	t.Run("Biz-Other", func(t *testing.T) {
		err := kerrors.ErrBiz.WithCause(errors.New("mock"))
		test.Assert(t, convertStatus(err).Code() == codes.Internal)
	})

	t.Run("GRPCStatusError", func(t *testing.T) {
		test.Assert(t, convertStatus(status.Err(102, "mock")).Code() == 102)
	})

	t.Run("TransError", func(t *testing.T) {
		test.Assert(t, convertStatus(remote.NewTransErrorWithMsg(103, "mock")).Code() == 103)
	})

	t.Run("basicError-conv-table-ACL", func(t *testing.T) {
		test.Assert(t, convertStatus(kerrors.ErrACL).Code() == codes.PermissionDenied)
	})

	t.Run("basicError-conv-table-ErrInternalException", func(t *testing.T) {
		test.Assert(t, convertStatus(kerrors.ErrInternalException).Code() == codes.Internal)
	})

	t.Run("basicError-conv-table-OverLimit", func(t *testing.T) {
		test.Assert(t, convertStatus(kerrors.ErrOverlimit).Code() == codes.ResourceExhausted)
	})

	t.Run("basicError-conv-table-RemoteOrNetwork", func(t *testing.T) {
		test.Assert(t, convertStatus(kerrors.ErrRemoteOrNetwork).Code() == codes.Unavailable)
	})

	t.Run("basicError-unknown", func(t *testing.T) {
		test.Assert(t, convertStatus(kerrors.ErrServiceDiscovery).Code() == codes.Internal)
	})

	t.Run("DetailedError-with-known-basicError", func(t *testing.T) {
		err := kerrors.ErrACL.WithCause(errors.New("mock"))
		test.Assert(t, convertStatus(err).Code() == codes.PermissionDenied)
	})

	t.Run("DetailedError-with-unknown-basicError", func(t *testing.T) {
		err := kerrors.ErrServiceDiscovery.WithCause(errors.New("mock"))
		test.Assert(t, convertStatus(err).Code() == codes.Internal)
	})

	t.Run("std-error", func(t *testing.T) {
		test.Assert(t, convertStatus(errors.New("mock")).Code() == codes.Internal)
	})

	t.Run("user-defined-error", func(t *testing.T) {
		test.Assert(t, convertStatus(&mockError{}).Code() == codes.Internal)
	})
}
