package activitytemplate

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

	"hyapp-admin-server/internal/integration/activityclient"
	"hyapp-admin-server/internal/middleware"
	activityv1 "hyapp.local/api/proto/activity/v1"

	"github.com/gin-gonic/gin"
)

type validatePermissionClient struct {
	activityclient.Client
}

func (validatePermissionClient) ValidateActivityTemplate(context.Context, *activityv1.ValidateActivityTemplateRequest) (*activityv1.ValidateActivityTemplateResponse, error) {
	return &activityv1.ValidateActivityTemplateResponse{Valid: true}, nil
}

func TestRegisterRoutesExposesActivityTemplateContract(t *testing.T) {
	gin.SetMode(gin.TestMode)
	engine := gin.New()
	RegisterRoutes(engine.Group("/api/v1"), &Handler{})

	actual := make(map[string]struct{})
	for _, route := range engine.Routes() {
		actual[route.Method+" "+route.Path] = struct{}{}
	}
	expected := []string{
		"GET /api/v1/admin/activities/templates",
		"POST /api/v1/admin/activities/templates",
		"POST /api/v1/admin/activities/templates/validate",
		"GET /api/v1/admin/activities/templates/:template_id",
		"PUT /api/v1/admin/activities/templates/:template_id",
		"PATCH /api/v1/admin/activities/templates/:template_id/status",
		"DELETE /api/v1/admin/activities/templates/:template_id",
		"GET /api/v1/admin/activities/templates/:template_id/versions",
		"POST /api/v1/admin/activities/templates/:template_id/clone",
		"GET /api/v1/admin/activities/templates/:template_id/leaderboard",
		"GET /api/v1/admin/activities/templates/:template_id/data",
		"GET /api/v1/admin/activities/templates/:template_id/data/export",
		"GET /api/v1/admin/activities/templates/:template_id/rewards",
		"POST /api/v1/admin/activities/templates/:template_id/rewards/:reward_job_id/retry",
		"GET /api/v1/admin/activities/templates/:template_id/task-claims",
		"POST /api/v1/admin/activities/templates/:template_id/task-claims/:claim_id/retry",
	}
	for _, route := range expected {
		if _, ok := actual[route]; !ok {
			t.Errorf("missing route %s; actual=%v", route, actual)
		}
	}
}

func TestValidateRouteAcceptsCreateUpdateOrPublishPermission(t *testing.T) {
	gin.SetMode(gin.TestMode)
	tests := []struct {
		permission string
		wantStatus int
	}{
		{permission: "activity-template:create", wantStatus: http.StatusOK},
		{permission: "activity-template:update", wantStatus: http.StatusOK},
		{permission: "activity-template:publish", wantStatus: http.StatusOK},
		{permission: "activity-template:view", wantStatus: http.StatusForbidden},
	}
	for _, tt := range tests {
		t.Run(tt.permission, func(t *testing.T) {
			engine := gin.New()
			engine.Use(func(c *gin.Context) {
				c.Set(middleware.ContextPermissions, []string{tt.permission})
				c.Next()
			})
			RegisterRoutes(engine.Group("/api/v1"), New(validatePermissionClient{}, nil))
			recorder := httptest.NewRecorder()
			request := httptest.NewRequest(http.MethodPost, "/api/v1/admin/activities/templates/validate", strings.NewReader(`{
				"template":{"template_code":"gift_challenge_2026","name":"Gift Challenge"},
				"for_publish":false
			}`))
			request.Header.Set("Content-Type", "application/json")

			engine.ServeHTTP(recorder, request)

			if recorder.Code != tt.wantStatus {
				t.Fatalf("status = %d, want %d; body=%s", recorder.Code, tt.wantStatus, recorder.Body.String())
			}
		})
	}
}
