package server

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

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

	"github.com/tidbcloud/AgentTeam/internal/config"
	"github.com/tidbcloud/AgentTeam/internal/service/automation"
	automationstore "github.com/tidbcloud/AgentTeam/internal/store/automation"
)

func TestAutomationRuntimeAPI(t *testing.T) {
	srv, err := New(config.ResourceRuntimeConfig{
		HTTPAddress: ":0",
		Auth:        config.ResourceRuntimeAuthConfig{Enabled: true, Header: "Authorization"},
		Database:    config.ResourceDatabaseConfig{DSN: meshxDatabaseDSN(t)},
		AGS:         config.AGSConfig{DatabaseDSN: prepareResolverDB(t), GitRepoDir: t.TempDir()},
	}, Options{AutomationAuthorizer: automation.AllowAutomationAuthorizer{}, NewAGS: func(agsconfig.Config, ...agsserver.Option) (agsServer, error) {
		automationYAML := "name: Runtime flow\nrun-name: Runtime flow\non:\n  manual: {}\njobs:\n  plan:\n    runs-on: ubuntu-latest\n    steps:\n      - id: first\n        run: echo checkout\n      - id: second\n        run: echo ok\n"
		commitSHA := "fedcba9876543210fedcba9876543210fedcba98"
		agsHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			switch {
			case r.URL.Path == "/api/v3/repos/pingcap/agentteam/git/refs/heads/main":
				_ = json.NewEncoder(w).Encode(map[string]any{"ref": "refs/heads/main", "object": map[string]any{"sha": commitSHA, "type": "commit"}})
			case r.URL.Path == "/api/v3/repos/pingcap/agentteam/contents/.agentteam/runtime.yml" && r.URL.Query().Get("ref") == commitSHA:
				_ = json.NewEncoder(w).Encode(map[string]any{"type": "file", "encoding": "base64", "content": base64.StdEncoding.EncodeToString([]byte(automationYAML))})
			default:
				http.NotFound(w, r)
			}
		})
		return fakeAGS{handler: agsHandler}, nil
	}})
	require.NoError(t, err)
	installLegacyAutomationSourceForTest(srv)
	t.Cleanup(func() { require.NoError(t, srv.Shutdown(context.Background())) })

	auth := "Bearer " + jwt(map[string]any{"sub": "user-1"})
	body, err := json.Marshal(map[string]string{
		"ref":            "refs/heads/main",
		"definitionPath": ".agentteam/runtime.yml",
		"inputJson":      `{"pr_url":"https://example.test/pr/1"}`,
	})
	require.NoError(t, err)

	startReq := httptest.NewRequest(http.MethodPost, "/api/v1/automations/repositories/pingcap/agentteam/runs", bytes.NewBuffer(body))
	startReq.Header.Set("Authorization", auth)
	startReq.Header.Set("X-Workspace-Id", "ws-runtime")
	startRec := httptest.NewRecorder()
	srv.handler.ServeHTTP(startRec, startReq)
	require.Equal(t, http.StatusCreated, startRec.Code, startRec.Body.String())
	require.False(t, srv.meshxDB.Migrator().HasTable("automation_definitions"))
	require.False(t, srv.meshxDB.Migrator().HasTable("automation_versions"))
	require.True(t, srv.meshxDB.Migrator().HasTable(&automationstore.AutomationJobRun{}))
	require.True(t, srv.meshxDB.Migrator().HasTable(&automationstore.AutomationJob{}))
	var run struct {
		ID                 string `json:"id"`
		SourceKind         string `json:"sourceKind"`
		RepositoryOwner    string `json:"repositoryOwner"`
		RepositoryName     string `json:"repositoryName"`
		RepositoryFullName string `json:"repositoryFullName"`
		DefinitionPath     string `json:"definitionPath"`
		GitRef             string `json:"gitRef"`
		CommitSHA          string `json:"commitSha"`
		DefinitionID       string `json:"definitionId"`
		Status             string `json:"status"`
	}
	require.NoError(t, json.Unmarshal(startRec.Body.Bytes(), &run))
	require.NotEmpty(t, run.ID)
	require.Equal(t, "agent_git_service_repo", run.SourceKind)
	require.Equal(t, "pingcap", run.RepositoryOwner)
	require.Equal(t, "agentteam", run.RepositoryName)
	require.Equal(t, "pingcap/agentteam", run.RepositoryFullName)
	require.Equal(t, ".agentteam/runtime.yml", run.DefinitionPath)
	require.Equal(t, "refs/heads/main", run.GitRef)
	require.Equal(t, "fedcba9876543210fedcba9876543210fedcba98", run.CommitSHA)
	require.Equal(t, "ags:pingcap/agentteam:.agentteam/runtime.yml", run.DefinitionID)
	require.Equal(t, "running", run.Status)

	var jobRuns []automationstore.AutomationJobRun
	require.NoError(t, srv.meshxDB.Where("workspace_id = ? AND run_id = ?", "ws-runtime", run.ID).Order("created_at ASC").Find(&jobRuns).Error)
	require.Len(t, jobRuns, 1)
	require.Equal(t, "plan", jobRuns[0].JobID)
	require.Equal(t, "github_actions_job", jobRuns[0].JobType)
	require.Equal(t, automationstore.AutomationJobRunStatusQueued, jobRuns[0].Status)
	require.Contains(t, jobRuns[0].InputJSON, "echo checkout")
	var jobs []automationstore.AutomationJob
	require.NoError(t, srv.meshxDB.Where("workspace_id = ? AND run_id = ?", "ws-runtime", run.ID).Find(&jobs).Error)
	require.Len(t, jobs, 1)
	require.Equal(t, run.ID+":"+jobRuns[0].JobID, jobs[0].IdempotencyKey)
}
