package repocache

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

	"github.com/stretchr/testify/require"
	service "github.com/tidbcloud/AgentTeam/internal/service/repocache"
	store "github.com/tidbcloud/AgentTeam/internal/store/repocache"
)

type fakeService struct {
	created service.CreateInput
	items   []store.Cache
	cancel  struct{ id, actor string }
}

func (s *fakeService) Create(_ context.Context, input service.CreateInput) (store.Cache, error) {
	s.created = input
	return store.Cache{ID: "prc_1", DisplayRemoteURL: input.RemoteURL, Status: store.StatusPending, AutoRefreshEnabled: input.AutoRefreshEnabled, RefreshIntervalSecs: input.RefreshIntervalSecs}, nil
}
func (s *fakeService) List(context.Context, int, int) ([]store.Cache, error) { return s.items, nil }
func (s *fakeService) Update(context.Context, string, service.UpdateInput) (store.Cache, error) {
	return store.Cache{}, nil
}
func (s *fakeService) Build(context.Context, string, string) (store.Cache, error) {
	return store.Cache{}, nil
}
func (s *fakeService) CancelBuild(_ context.Context, id, actor string) (store.Cache, error) {
	s.cancel.id, s.cancel.actor = id, actor
	return store.Cache{ID: id, Status: store.StatusCancelled, LastError: "build cancelled"}, nil
}
func (s *fakeService) Delete(context.Context, string) error { return nil }

func TestInternalAdminRoutesRequireServiceToken(t *testing.T) {
	mux := http.NewServeMux()
	RegisterRoutes(mux, NewHandler(&fakeService{}, "admin-token"))

	req := httptest.NewRequest(http.MethodGet, "/internal/admin/public-repository-caches", nil)
	rec := httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	require.Equal(t, http.StatusUnauthorized, rec.Code)

	req = httptest.NewRequest(http.MethodGet, "/internal/admin/public-repository-caches", nil)
	req.Header.Set("Authorization", "Bearer admin-token")
	rec = httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	require.Equal(t, http.StatusOK, rec.Code)
}

func TestCancelBuildPassesCacheAndActor(t *testing.T) {
	fake := &fakeService{}
	mux := http.NewServeMux()
	RegisterRoutes(mux, NewHandler(fake, "admin-token"))
	req := httptest.NewRequest(http.MethodPost, "/internal/admin/public-repository-caches/prc_1/cancel", nil)
	req.Header.Set("Authorization", "Bearer admin-token")
	req.Header.Set("X-Ops-Actor", "ops-user")
	rec := httptest.NewRecorder()

	mux.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code)
	require.Equal(t, "prc_1", fake.cancel.id)
	require.Equal(t, "ops-user", fake.cancel.actor)
	require.Contains(t, rec.Body.String(), "build cancelled")
}

func TestCreatePassesOpsActorAndReturnsDTO(t *testing.T) {
	fake := &fakeService{}
	mux := http.NewServeMux()
	RegisterRoutes(mux, NewHandler(fake, "admin-token"))
	req := httptest.NewRequest(http.MethodPost, "/internal/admin/public-repository-caches", strings.NewReader(`{"remoteUrl":"https://github.com/pingcap/tidb.git","autoRefreshEnabled":true,"refreshIntervalSeconds":3600}`))
	req.Header.Set("Authorization", "Bearer admin-token")
	req.Header.Set("X-Ops-Actor", "ops-user")
	rec := httptest.NewRecorder()

	mux.ServeHTTP(rec, req)

	require.Equal(t, http.StatusCreated, rec.Code)
	require.Equal(t, "ops-user", fake.created.Actor)
	require.JSONEq(t, `{"id":"prc_1","remoteUrl":"https://github.com/pingcap/tidb.git","status":"pending","autoRefreshEnabled":true,"refreshIntervalSeconds":3600,"info":{}}`, rec.Body.String())
}

func TestListReturnsPersistedCacheInfo(t *testing.T) {
	fake := &fakeService{items: []store.Cache{{ID: "prc_1", Status: store.StatusReady, Info: `{"sizeBytes":123456}`}}}
	mux := http.NewServeMux()
	RegisterRoutes(mux, NewHandler(fake, "admin-token"))
	req := httptest.NewRequest(http.MethodGet, "/internal/admin/public-repository-caches", nil)
	req.Header.Set("Authorization", "Bearer admin-token")
	rec := httptest.NewRecorder()

	mux.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code)
	require.JSONEq(t, `{"items":[{"id":"prc_1","remoteUrl":"","status":"ready","autoRefreshEnabled":false,"refreshIntervalSeconds":0,"info":{"sizeBytes":123456}}]}`, rec.Body.String())
}
