package org

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

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

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

type codexAuthTestOrganizationProvider struct {
	OrganizationProvider
	provider organization.OrganizationProviderView
	err      error
}

func (provider *codexAuthTestOrganizationProvider) GetOrganizationProviderForUser(context.Context, string, string, string) (organization.OrganizationProviderView, error) {
	if provider.err != nil {
		return organization.OrganizationProviderView{}, provider.err
	}
	return provider.provider, nil
}

type codexAuthTestRegistry struct {
	snapshots  []agentteambridge.CodexAuthSnapshot
	configured bool
	results    []agentteambridge.CodexAuthRefreshResult
}

func (registry *codexAuthTestRegistry) Refresh(context.Context) error { return nil }

func (registry *codexAuthTestRegistry) CodexAuthSnapshots(string, string) ([]agentteambridge.CodexAuthSnapshot, bool) {
	return append([]agentteambridge.CodexAuthSnapshot(nil), registry.snapshots...), registry.configured
}

func (registry *codexAuthTestRegistry) ForceRefreshCodexAuth(context.Context, string, string, string) ([]agentteambridge.CodexAuthRefreshResult, bool) {
	return append([]agentteambridge.CodexAuthRefreshResult(nil), registry.results...), registry.configured
}

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

	orgs := &codexAuthTestOrganizationProvider{
		provider: organization.OrganizationProviderView{ID: "opvd_1", DriverKind: "codex"},
	}
	registry := &codexAuthTestRegistry{configured: false}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   registry,
	}}

	router := gin.New()
	router.GET("/api/v1/orgs/:orgId/providers/:providerId/codex/auth", func(ctx *gin.Context) {
		api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
		handler.CodexAuthGet(ctx)
	})

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodGet, "/api/v1/orgs/org_1/providers/opvd_1/codex/auth", nil)
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.JSONEq(t, `{"configured":false,"auth":[],"totalCount":0}`, recorder.Body.String())
}

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

	orgs := &codexAuthTestOrganizationProvider{
		provider: organization.OrganizationProviderView{ID: "opvd_1", DriverKind: "codex"},
	}
	registry := &codexAuthTestRegistry{
		configured: true,
		snapshots: []agentteambridge.CodexAuthSnapshot{{
			Source:          "primary",
			Name:            "main",
			BackendID:       7,
			BaseURL:         "https://chatgpt.test",
			Mode:            "chatgpt",
			Active:          true,
			Weight:          2,
			AllowedAPIKeys:  []string{"sk-live****1234"},
			HasAccessToken:  true,
			HasRefreshToken: true,
			AccessToken:     "sess****abcd",
			AccountID:       "acct_1",
			LastRefreshAt:   "2026-05-08T12:00:00Z",
			LastStatus:      http.StatusOK,
		}},
	}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   registry,
	}}

	router := gin.New()
	router.GET("/api/v1/orgs/:orgId/providers/:providerId/codex/auth", func(ctx *gin.Context) {
		api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
		handler.CodexAuthGet(ctx)
	})

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodGet, "/api/v1/orgs/org_1/providers/opvd_1/codex/auth", nil)
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.Contains(t, recorder.Body.String(), `"configured":true`)
	require.Contains(t, recorder.Body.String(), `"backendId":7`)
	require.Contains(t, recorder.Body.String(), `"hasRefreshToken":true`)
	require.Contains(t, recorder.Body.String(), `"totalCount":1`)
}

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

	orgs := &codexAuthTestOrganizationProvider{
		provider: organization.OrganizationProviderView{ID: "opvd_1", DriverKind: "codex"},
	}
	registry := &codexAuthTestRegistry{
		configured: true,
		results: []agentteambridge.CodexAuthRefreshResult{
			{Source: "primary", Refreshed: true},
			{Source: "primary.auth_files.0", Error: "refresh failed"},
		},
	}
	handler := &ProviderHandler{organizationHandlerBase: organizationHandlerBase{
		organizations: orgs,
		llmRegistry:   registry,
	}}

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

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodPost, "/api/v1/orgs/org_1/providers/opvd_1/codex/auth/refresh", strings.NewReader(`{"source":"primary"}`))
	request.Header.Set("Content-Type", "application/json")
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusBadGateway, recorder.Code)
	require.Contains(t, recorder.Body.String(), `"source":"primary.auth_files.0"`)
	require.Contains(t, recorder.Body.String(), `"error":"refresh failed"`)
}
