package repotokens_test

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/glebarez/sqlite"
	"github.com/stretchr/testify/require"
	"gorm.io/gorm"

	api "github.com/tidbcloud/AgentTeam/internal/api/repotokens"
	"github.com/tidbcloud/AgentTeam/internal/identity/trusted"
	"github.com/tidbcloud/AgentTeam/internal/service/repotokens"
	store "github.com/tidbcloud/AgentTeam/internal/store/repotokens"
)

func handlerService(t *testing.T) *repotokens.Service {
	t.Helper()
	db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&store.Token{}, &store.Event{}, &store.AgentSuppression{}))
	return repotokens.NewService(store.New(db), nil)
}

func TestHandlerMeshXOwnsHumanTokenLifecycle(t *testing.T) {
	mux := http.NewServeMux()
	api.RegisterRoutes(mux, api.NewHandler(handlerService(t)), trusted.Middleware(trusted.Options{Enabled: true, Header: "Authorization"}))
	body := bytes.NewBufferString(`{"displayName":"Docs","providerHost":"github.com","repositoryScope":{"mode":"repositories","repositories":["pingcap/agentteam"]},"capabilities":["repo:read"]}`)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/repository-access-tokens", body)
	req.Header.Set("Authorization", "Bearer "+jwt(map[string]any{"sub": "usr_1", "workspace_ids": []string{"wsp_1"}, "automation_permissions": []string{"automation:*"}}))
	req.Header.Set("X-Workspace-Id", "wsp_1")
	rec := httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	require.Equal(t, http.StatusCreated, rec.Code, rec.Body.String())
	require.Contains(t, rec.Body.String(), `"plaintext":"ags_rat_`)
	require.NotContains(t, rec.Body.String(), "ags_contract_missing")
}

func TestHandlerRejectsCreateWithoutWorkspaceGateContext(t *testing.T) {
	mux := http.NewServeMux()
	api.RegisterRoutes(mux, api.NewHandler(handlerService(t)), trusted.Middleware(trusted.Options{Enabled: true, Header: "Authorization"}))
	body := bytes.NewBufferString(`{"displayName":"Docs","providerHost":"github.com","repositoryScope":{"mode":"repositories","repositories":["pingcap/agentteam"]},"capabilities":["repo:read"]}`)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/repository-access-tokens", body)
	req.Header.Set("Authorization", "Bearer "+jwt(map[string]any{"sub": "usr_1"}))
	rec := httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	require.Equal(t, http.StatusForbidden, rec.Code)
	require.Contains(t, rec.Body.String(), `"error":"permission_denied"`)
	require.NotContains(t, rec.Body.String(), "ags_rat_")
}

func TestHandlerInternalAgentLifecycleReconcilesExplicitPermissionMode(t *testing.T) {
	mux := http.NewServeMux()
	api.RegisterRoutes(mux, api.NewHandler(handlerService(t)), trusted.Middleware(trusted.Options{Enabled: true, Header: "Authorization"}))
	body := bytes.NewBufferString(`{"providerHost":"github.example.com","repositoryScope":{"mode":"repositories","repositories":["pingcap/agentteam"]},"permissionMode":"agent_workspace_write","reason":"agent_created"}`)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/internal/repository-access-tokens/agents/agt_1/reconcile", body)
	req.Header.Set("Authorization", "Bearer "+jwt(map[string]any{"sub": "usr_1", "workspace_ids": []string{"wsp_1"}, "automation_permissions": []string{"automation:runner:manage"}}))
	req.Header.Set("X-Workspace-Id", "wsp_1")
	rec := httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())
	require.Contains(t, rec.Body.String(), `"type":"agent"`)
	require.Contains(t, rec.Body.String(), `"capabilities":["repo:read","repo:clone"]`)
}

func jwt(claims map[string]any) string {
	header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"none"}`))
	payload, _ := json.Marshal(claims)
	return header + "." + base64.RawURLEncoding.EncodeToString(payload) + "."
}
