package schedule

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

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api/testkit/httputil"
	"github.com/tidbcloud/AgentTeam/internal/schedule/manage"
)

func TestRegisterRoutesOwnsScheduleRoutes(t *testing.T) {
	t.Parallel()

	router := gin.New()
	RegisterRoutes(router, Dependencies{})

	counts := httputil.RouteCounts(router)
	for _, route := range scheduleRouteKeys() {
		require.Equal(t, 1, counts[route], route)
	}
}

func scheduleRouteKeys() []string {
	return []string{
		"GET /api/v1/workspaces/:workspaceId/schedules",
		"POST /api/v1/workspaces/:workspaceId/schedules",
		"POST /api/v1/workspaces/:workspaceId/schedules:validate",
		"GET /api/v1/workspaces/:workspaceId/schedules/:scheduleId",
		"PATCH /api/v1/workspaces/:workspaceId/schedules/:scheduleId",
		"POST /api/v1/workspaces/:workspaceId/schedules/:scheduleAction",
		"DELETE /api/v1/workspaces/:workspaceId/schedules/:scheduleId",
		"GET /api/v1/workspaces/:workspaceId/schedules/:scheduleId/runs",
	}
}

func TestListRequestFromRequestEnablesCursorPaging(t *testing.T) {
	t.Parallel()

	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest("GET", "/?page=true&limit=100&cursor=200", nil)

	request, err := listRequestFromRequest(ctx)
	require.NoError(t, err)
	require.True(t, request.page)
	require.Equal(t, 100, request.limit)
	require.Equal(t, "200", request.cursor)
	require.Equal(t, 101, request.filter.Limit)
	require.Equal(t, 200, request.filter.Offset)
	require.True(t, request.filter.Page)
}

func TestListRequestFromRequestParsesTargetScope(t *testing.T) {
	t.Parallel()

	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest("GET", "/?page=true&target_kind=channel&target_ref=chn_1&include_child_threads=true", nil)

	request, err := listRequestFromRequest(ctx)
	require.NoError(t, err)
	require.Equal(t, manage.TargetKindChannel, request.filter.TargetKind)
	require.Equal(t, "chn_1", request.filter.TargetRef)
	require.True(t, request.filter.IncludeChildThreads)
}

func TestListRequestFromRequestRejectsIncompleteTargetScope(t *testing.T) {
	t.Parallel()

	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest("GET", "/?page=true&target_kind=channel", nil)

	_, err := listRequestFromRequest(ctx)
	require.EqualError(t, err, "target_kind and target_ref must be provided together")
}

func TestListRequestFromRequestRejectsChildThreadsForThreadTarget(t *testing.T) {
	t.Parallel()

	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest("GET", "/?page=true&target_kind=reply_thread&target_ref=thr_1&include_child_threads=true", nil)

	_, err := listRequestFromRequest(ctx)
	require.EqualError(t, err, "include_child_threads requires a channel or DM target")
}

func TestCollectionListReturnsCursorPage(t *testing.T) {
	t.Parallel()

	result := make([]manage.ScheduleView, 101)
	page := schedulePageResponse(result, scheduleListRequest{
		filter: manage.ListFilter{
			Limit:  101,
			Offset: 200,
			Page:   true,
		},
		limit:  100,
		cursor: "200",
		page:   true,
	})

	require.Len(t, page.Schedules, 100)
	require.Equal(t, 100, page.Limit)
	require.Equal(t, "200", page.Cursor)
	require.True(t, page.HasMore)
	require.Equal(t, "300", page.NextCursor)
}

func TestListRequestFromRequestUsesArrayResponseModeWithoutPaging(t *testing.T) {
	t.Parallel()

	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest("GET", "/?limit=100", nil)

	request, err := listRequestFromRequest(ctx)
	require.NoError(t, err)
	require.False(t, request.page)
	require.Equal(t, 100, request.limit)
	require.Equal(t, 100, request.filter.Limit)
	require.Zero(t, request.filter.Offset)
	require.False(t, request.filter.Page)
}

func TestListRequestFromRequestRejectsInvalidCursor(t *testing.T) {
	t.Parallel()

	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest("GET", "/?page=true&cursor=not-an-offset", nil)

	_, err := listRequestFromRequest(ctx)
	require.EqualError(t, err, "invalid cursor")
}
