package task

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
)

// taskSubtasksPageDefaultLimit preserves the current 10-row initial detail
// behavior for the direct-children section. It must stay in sync with
// taskboard.TaskSubtasksDefaultPageSize.
const taskSubtasksPageDefaultLimit = 10

// taskSubtasksPageMaxLimit caps a single direct-children page. It must stay in
// sync with taskboard.TaskSubtasksMaxPageSize.
const taskSubtasksPageMaxLimit = 100

// List handles GET /api/v1/workspaces/:workspaceId/tasks/:taskId/subtasks.
// It returns one bounded keyset page of the parent task's direct children in
// newest-first order (created_at DESC, id DESC) as {tasks, hasMore,
// nextCursor}. The parent is read-authorized before enumeration, so workspace
// isolation, parent relation, channel permission checks, and the current
// 403/404 non-enumeration behavior are preserved.
func (handler *SubtaskHandler) List(r api.WorkspaceScopedRequest) (api.Response, error) {
	taskID := strings.TrimSpace(r.Gin.Param("taskId"))
	if taskID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "taskId is required")
	}

	limit, err := parseTaskSubtasksPageLimit(r)
	if err != nil {
		return api.Response{}, err
	}
	cursor, err := parseTaskSubtasksPageCursor(r)
	if err != nil {
		return api.Response{}, err
	}

	response, err := handler.taskBoard.ListTaskSubtasks(r.Context(), ListTaskSubtasksRequest{
		Context: NewUserServiceContext(r.WorkspaceID(), r.User.User.ID, r.User.User.Name),
		Task:    TaskRef{TaskID: taskID},
		Limit:   limit,
		Cursor:  cursor,
	})
	if err != nil {
		return api.Response{}, err
	}

	return api.OK(converter.ToTaskSubtasksPageResponse(taskboardListTaskSubtasksResponseForDTO(response))), nil
}

// parseTaskSubtasksPageLimit validates the optional limit query parameter.
// A blank limit selects the named default; a non-integer, non-positive, or
// over-max limit is rejected with 400 rather than silently coerced.
func parseTaskSubtasksPageLimit(r api.WorkspaceScopedRequest) (int, error) {
	raw := strings.TrimSpace(r.Gin.Query("limit"))
	if raw == "" {
		return taskSubtasksPageDefaultLimit, nil
	}
	limit, err := strconv.Atoi(raw)
	if err != nil {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit must be a positive integer")
	}
	if limit <= 0 {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit must be a positive integer")
	}
	if limit > taskSubtasksPageMaxLimit {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit exceeds the maximum page size")
	}
	return limit, nil
}

// parseTaskSubtasksPageCursor decodes the optional cursor query parameter.
// A blank cursor selects the first page; a malformed or incomplete cursor is
// rejected with 400.
func parseTaskSubtasksPageCursor(r api.WorkspaceScopedRequest) (TaskSubtaskCursor, error) {
	raw := strings.TrimSpace(r.Gin.Query("cursor"))
	if raw == "" {
		return TaskSubtaskCursor{}, nil
	}
	cursor, err := converter.FromTaskSubtasksCursorToken(raw)
	if err != nil {
		return TaskSubtaskCursor{}, api.NewHTTPError(http.StatusBadRequest, err.Error())
	}
	return taskSubtaskCursorForDTO(cursor), nil
}

// Create handles POST /api/tasks/:taskId/subtasks.
// It creates one or more subtasks under a parent task.
func (handler *SubtaskHandler) Create(r api.WorkspaceScopedJSON[dto.TaskCreateSubtasksRequest]) (api.Response, error) {
	request := r.Body
	authenticated := r.User

	taskID := strings.TrimSpace(r.Gin.Param("taskId"))
	if taskID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "taskId is required")
	}

	createRequest := CreateSubtasksRequest{
		Context: NewUserServiceContext(r.WorkspaceID(), authenticated.User.ID, authenticated.User.Name),
		Task:    TaskRef{TaskID: taskID},
	}
	if request.Task != nil {
		createRequest.Input = taskCreateInputForPort(converter.FromTaskCreateInput(request.Task))
	} else {
		titles := make([]string, 0, len(request.Tasks))
		for _, task := range request.Tasks {
			titles = append(titles, task.Title)
		}
		createRequest.Titles = titles
	}

	response, err := handler.taskBoard.CreateSubtasks(r.Context(), createRequest)
	if err != nil {
		return api.Response{}, err
	}

	return api.OK(dto.TaskPageResponse{Tasks: converter.ToTasksEmpty(taskboardTasksForDTO(response.Tasks))}), nil
}
