package org

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"
)

type grantTestOrganizationProvider struct {
	OrganizationProvider
	providerGrantResult organization.OrganizationWorkspaceProviderGrantView
	routeGrantResult    organization.OrganizationWorkspaceRouteGrantView
	providerGrantCalls  int
	providerRevokeCalls int
	routeGrantCalls     int
	routeRevokeCalls    int
}

func (provider *grantTestOrganizationProvider) GrantOrganizationWorkspaceProviderForUser(ctx context.Context, userID string, organizationID string, workspaceID string, providerID string) (organization.OrganizationWorkspaceProviderGrantView, error) {
	provider.providerGrantCalls++
	return provider.providerGrantResult, nil
}

func (provider *grantTestOrganizationProvider) RevokeOrganizationWorkspaceProviderForUser(ctx context.Context, userID string, organizationID string, workspaceID string, providerID string) error {
	provider.providerRevokeCalls++
	return nil
}

func (provider *grantTestOrganizationProvider) GrantOrganizationWorkspaceRouteForUser(ctx context.Context, userID string, organizationID string, workspaceID string, routeID string) (organization.OrganizationWorkspaceRouteGrantView, error) {
	provider.routeGrantCalls++
	return provider.routeGrantResult, nil
}

func (provider *grantTestOrganizationProvider) RevokeOrganizationWorkspaceRouteForUser(ctx context.Context, userID string, organizationID string, workspaceID string, routeID string) error {
	provider.routeRevokeCalls++
	return nil
}

func TestProviderHandlerWorkspaceGrantCreateRefreshesLLMRegistry(t *testing.T) {
	t.Parallel()

	orgs := &grantTestOrganizationProvider{
		providerGrantResult: organization.OrganizationWorkspaceProviderGrantView{
			WorkspaceID: "ws_1",
			ProviderID:  "opvd_1",
		},
	}
	refresher := &tokenTestRefresher{}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   refresher,
	}}

	router := gin.New()
	router.POST("/api/v1/orgs/:orgId/workspaces/:workspaceId/providers/:providerId", func(ctx *gin.Context) {
		api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
		handler.WorkspaceGrantCreate(ctx)
	})

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodPost, "/api/v1/orgs/org_1/workspaces/ws_1/providers/opvd_1", nil)
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.Equal(t, 1, orgs.providerGrantCalls)
	require.Equal(t, 1, refresher.calls)
}

func TestProviderHandlerWorkspaceGrantDeleteRefreshesLLMRegistry(t *testing.T) {
	t.Parallel()

	orgs := &grantTestOrganizationProvider{}
	refresher := &tokenTestRefresher{}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   refresher,
	}}

	router := gin.New()
	router.DELETE("/api/v1/orgs/:orgId/workspaces/:workspaceId/providers/:providerId", func(ctx *gin.Context) {
		api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
		handler.WorkspaceGrantDelete(ctx)
	})

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodDelete, "/api/v1/orgs/org_1/workspaces/ws_1/providers/opvd_1", nil)
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.Equal(t, 1, orgs.providerRevokeCalls)
	require.Equal(t, 1, refresher.calls)
}

func TestProviderHandlerWorkspaceRouteGrantCreateRefreshesLLMRegistry(t *testing.T) {
	t.Parallel()

	orgs := &grantTestOrganizationProvider{
		routeGrantResult: organization.OrganizationWorkspaceRouteGrantView{
			WorkspaceID: "ws_1",
			RouteID:     "oprt_1",
		},
	}
	refresher := &tokenTestRefresher{}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   refresher,
	}}

	router := gin.New()
	router.POST("/api/v1/orgs/:orgId/workspaces/:workspaceId/provider-routes/:routeId", func(ctx *gin.Context) {
		api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
		handler.WorkspaceRouteGrantCreate(ctx)
	})

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodPost, "/api/v1/orgs/org_1/workspaces/ws_1/provider-routes/oprt_1", nil)
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.Equal(t, 1, orgs.routeGrantCalls)
	require.Equal(t, 1, refresher.calls)
}

func TestProviderHandlerWorkspaceRouteGrantDeleteRefreshesLLMRegistry(t *testing.T) {
	t.Parallel()

	orgs := &grantTestOrganizationProvider{}
	refresher := &tokenTestRefresher{}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   refresher,
	}}

	router := gin.New()
	router.DELETE("/api/v1/orgs/:orgId/workspaces/:workspaceId/provider-routes/:routeId", func(ctx *gin.Context) {
		api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
		handler.WorkspaceRouteGrantDelete(ctx)
	})

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodDelete, "/api/v1/orgs/org_1/workspaces/ws_1/provider-routes/oprt_1", nil)
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.Equal(t, 1, orgs.routeRevokeCalls)
	require.Equal(t, 1, refresher.calls)
}
