package server

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"google.golang.org/protobuf/types/known/timestamppb"
)

func Test_OAuthStateParam_IsValid(t *testing.T) {
	tests := []struct {
		name            string
		oauthStateParam *OAuthStateParam
		host            string
		expected        bool
	}{
		{
			name: "valid",
			oauthStateParam: &OAuthStateParam{
				CreatedAt: timestamppb.Now(),
			},
			expected: true,
		},
		{
			name: "expired",
			oauthStateParam: &OAuthStateParam{
				CreatedAt: timestamppb.New(time.Now().Add(-10 * time.Minute)),
			},
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.oauthStateParam.IsValid(oauthStateTTL)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func Test_OAuthState_IsValid(t *testing.T) {
	tests := []struct {
		name       string
		oauthState *OAuthState
		state      string
		expected   bool
	}{
		{
			name: "valid",
			oauthState: &OAuthState{
				StateValue: "123",
				CreatedAt:  timestamppb.Now(),
			},
			state:    "123",
			expected: true,
		},
		{
			name: "state mismatch",
			oauthState: &OAuthState{
				StateValue: "123",
				CreatedAt:  timestamppb.Now(),
			},
			state:    "456",
			expected: false,
		},
		{
			name: "expired",
			oauthState: &OAuthState{
				StateValue: "123",
				CreatedAt:  timestamppb.New(time.Now().Add(-10 * time.Minute)),
			},
			state:    "123",
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.oauthState.IsValid(oauthStateTTL, tt.state)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func Test_TransferError_IsValid(t *testing.T) {
	tests := []struct {
		name          string
		transferErr   *TransferError
		host          string
		expectedValid bool
		expectedError bool
	}{
		{
			name: "valid",
			transferErr: &TransferError{
				OriginalUrl: "https://5000-w1.workspaces.test/123",
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: true,
		},
		{
			name: "host mismatch",
			transferErr: &TransferError{
				OriginalUrl: "https://different.example.com/123",
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: false,
		},
		{
			name: "invalid url",
			transferErr: &TransferError{
				OriginalUrl: "https://different.example.com\n/123",
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: false,
			expectedError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			valid, err := tt.transferErr.IsValid(tt.host)
			if tt.expectedError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
			assert.Equal(t, tt.expectedValid, valid)
		})
	}
}

func Test_TransferToken_IsValid(t *testing.T) {
	tests := []struct {
		name          string
		transferToken *TransferToken
		host          string
		expectedValid bool
		expectedError bool
	}{
		{
			name: "valid",
			transferToken: &TransferToken{
				OriginalUrl: "https://5000-w1.workspaces.test/123",
				CreatedAt:   timestamppb.Now(),
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: true,
		},
		{
			name: "host mismatch",
			transferToken: &TransferToken{
				OriginalUrl: "https://different.example.com/123",
				CreatedAt:   timestamppb.Now(),
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: false,
		},
		{
			name: "invalid url",
			transferToken: &TransferToken{
				OriginalUrl: "https://different.example.com\n/123",
				CreatedAt:   timestamppb.Now(),
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: false,
			expectedError: true,
		},
		{
			name: "expired",
			transferToken: &TransferToken{
				OriginalUrl: "https://5000-w1.workspaces.test/123",
				CreatedAt:   timestamppb.New(time.Now().Add(-2 * time.Minute)),
			},
			host:          "5000-w1.workspaces.test",
			expectedValid: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			valid, err := tt.transferToken.IsValid(transferTokenTTL, tt.host)
			if tt.expectedError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
			assert.Equal(t, tt.expectedValid, valid)
		})
	}
}

func Test_UserSession_IsValid(t *testing.T) {
	tests := []struct {
		name        string
		userSession *UserSession
		host        string
		expected    bool
	}{
		{
			name: "valid session",
			userSession: &UserSession{
				Host:      "5000-w1.workspaces.test",
				CreatedAt: timestamppb.Now(),
			},
			host:     "5000-w1.workspaces.test",
			expected: true,
		},
		{
			name: "host mismatch",
			userSession: &UserSession{
				Host:      "different.example.com",
				CreatedAt: timestamppb.Now(),
			},
			host:     "5000-w1.workspaces.test",
			expected: false,
		},
		{
			name: "expired session",
			userSession: &UserSession{
				Host:      "5000-w1.workspaces.test",
				CreatedAt: timestamppb.New(time.Now().Add(-25 * time.Hour)),
			},
			host:     "5000-w1.workspaces.test",
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.userSession.IsValid(userSessionTTL, tt.host)
			assert.Equal(t, tt.expected, result)
		})
	}
}
