package server

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"testing"
	"time"

	agsserver "github.com/pingcap/agent-git-service/server"
	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/agsbridge"
	"github.com/tidbcloud/AgentTeam/internal/database"
	"github.com/tidbcloud/AgentTeam/internal/service/automation"
	automationstore "github.com/tidbcloud/AgentTeam/internal/store/automation"
	"github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
)

func TestAGSAutomationBranchUpdateBridgeStartsRunsForMappedWorkspaceRepo(t *testing.T) {
	const (
		workspaceID = "ws-ags-merge"
		repoOwner   = "ws-ags-merge"
		repoName    = "agentteam.kb"
		afterSHA    = "abababababababababababababababababababab"
	)
	db, err := database.Open(database.Config{DSN: meshxDatabaseDSN(t)})
	require.NoError(t, err)
	t.Cleanup(func() { require.NoError(t, database.Close(db)) })

	automationYAML := "name: Push build\non:\n  push:\n    branches: [main]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - run: echo build\n"
	var seenAuth string
	agsHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		seenAuth = r.Header.Get("Authorization")
		switch {
		case r.URL.Path == "/api/v3/repos/"+repoOwner+"/"+repoName+"/contents/.agentteam":
			require.Equal(t, afterSHA, r.URL.Query().Get("ref"))
			require.NoError(t, json.NewEncoder(w).Encode([]map[string]any{{
				"type": "file",
				"name": "push.yml",
				"path": ".agentteam/push.yml",
				"sha":  "content-sha",
				"size": len([]byte(automationYAML)),
			}}))
		case r.URL.Path == "/api/v3/repos/"+repoOwner+"/"+repoName+"/commits/"+afterSHA:
			require.NoError(t, json.NewEncoder(w).Encode(map[string]any{"sha": afterSHA}))
		case r.URL.Path == "/api/v3/repos/"+repoOwner+"/"+repoName+"/contents/.agentteam/push.yml":
			require.Equal(t, afterSHA, r.URL.Query().Get("ref"))
			require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
				"type":     "file",
				"name":     "push.yml",
				"path":     ".agentteam/push.yml",
				"size":     len([]byte(automationYAML)),
				"encoding": "base64",
				"content":  base64.StdEncoding.EncodeToString([]byte(automationYAML)),
			}))
		default:
			http.NotFound(w, r)
		}
	})

	automationRuns := automationstore.New(db)
	repoStore := repos.New(db)
	automationService := automation.NewAutomationsService(automationRuns, func() time.Time { return time.Now().UTC() }, automation.AGSHTTPAutomationSourceResolver{Handler: agsHandler, AuthHeader: "Authorization"})
	automationService.SetRepositoryStore(repoStore)
	automationService.SetAuthorizer(automation.AllowAutomationAuthorizer{})

	now := time.Now().UTC()
	_, err = repoStore.Upsert(context.Background(), repos.ResourceRepository{
		ID:           "rr_1",
		WorkspaceID:  workspaceID,
		ResourceType: repos.ResourceTypeAutomationRepository,
		ResourceID:   repos.AutomationRepositoryResourceID(repoOwner + "/" + repoName),
		RepoRole:     repos.RepoRolePrimary,
		OwnerKind:    "automation_repository",
		RepoOwner:    repoOwner,
		RepoName:     repoName,
		RepoFullName: repoOwner + "/" + repoName,
		AGSRepoID:    "repo_1",
		DefaultRef:   "main",
		Visibility:   "private",
		UserVisible:  true,
		CreatedBy:    "owner",
		UpdatedBy:    "owner",
		CreatedAt:    now,
		UpdatedAt:    now,
	})
	require.NoError(t, err)

	bridge := newAGSAutomationBranchUpdateBridge(repoStore, automationService, agsbridge.AuthorizationHeader())
	err = bridge.processRepositoryEvent(context.Background(), agsserver.RepositoryEvent{
		RepositoryID: 1,
		Event:        "push",
		PayloadJSON:  []byte(`{"ref":"refs/heads/main","before":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","after":"` + afterSHA + `","repository":{"full_name":"` + repoOwner + `/` + repoName + `"},"sender":{"login":"alice","name":"Alice"}}`),
	})
	require.NoError(t, err)
	require.Equal(t, agsbridge.AuthorizationHeader(), seenAuth)

	result, err := automationRuns.ListRuns(context.Background(), workspaceID, "", repoOwner+"/"+repoName, "", 1, 10)
	require.NoError(t, err)
	require.Len(t, result.Runs, 1)
	run := result.Runs[0]
	require.Equal(t, ".agentteam/push.yml", run.DefinitionPath)
	require.Equal(t, afterSHA, run.CommitSHA)
	require.Equal(t, "push", run.TriggerKind)
	require.NotEmpty(t, run.TriggerRef)
	require.Equal(t, repoOwner+"/"+repoName, run.RepositoryFullName)
	require.Contains(t, run.InputJSON, `"ref":"refs/heads/main"`)
}

func TestAGSAutomationBranchUpdateBridgeIgnoresKBSourceMappings(t *testing.T) {
	const (
		workspaceID = "ws-native-kb"
		repoOwner   = "ws-native-kb"
		repoName    = "agentteam.kb"
		afterSHA    = "abababababababababababababababababababab"
	)
	db, err := database.Open(database.Config{DSN: meshxDatabaseDSN(t)})
	require.NoError(t, err)
	t.Cleanup(func() { require.NoError(t, database.Close(db)) })

	agsCalls := 0
	automationRuns := automationstore.New(db)
	repoStore := repos.New(db)
	automationService := automation.NewAutomationsService(automationRuns, func() time.Time { return time.Now().UTC() }, automation.AGSHTTPAutomationSourceResolver{Handler: http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
		agsCalls++
	}), AuthHeader: "Authorization"})
	automationService.SetRepositoryStore(repoStore)
	automationService.SetAuthorizer(automation.AllowAutomationAuthorizer{})

	now := time.Now().UTC()
	_, err = repoStore.Upsert(context.Background(), repos.ResourceRepository{
		ID:           "rr_native_kb",
		WorkspaceID:  workspaceID,
		ResourceType: repos.ResourceTypeKBSource,
		ResourceID:   "src_native",
		RepoRole:     repos.RepoRolePrimary,
		OwnerKind:    "knowledge_base_source",
		RepoOwner:    repoOwner,
		RepoName:     repoName,
		RepoFullName: repoOwner + "/" + repoName,
		AGSRepoID:    "repo_native_kb",
		DefaultRef:   "main",
		Visibility:   "private",
		UserVisible:  true,
		CreatedBy:    "owner",
		UpdatedBy:    "owner",
		CreatedAt:    now,
		UpdatedAt:    now,
	})
	require.NoError(t, err)

	bridge := newAGSAutomationBranchUpdateBridge(repoStore, automationService, agsbridge.AuthorizationHeader())
	err = bridge.processRepositoryEvent(context.Background(), agsserver.RepositoryEvent{
		RepositoryID: 1,
		Event:        "push",
		PayloadJSON:  []byte(`{"ref":"refs/heads/main","before":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","after":"` + afterSHA + `","repository":{"full_name":"` + repoOwner + `/` + repoName + `"},"sender":{"login":"alice","name":"Alice"}}`),
	})
	require.NoError(t, err)
	require.Zero(t, agsCalls, "KB source events must not invoke the legacy Automation AGS source resolver")

	result, err := automationRuns.ListRuns(context.Background(), workspaceID, "", repoOwner+"/"+repoName, "", 1, 10)
	require.NoError(t, err)
	require.Empty(t, result.Runs)
}
