package channel

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

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	storechannel "github.com/tidbcloud/AgentTeam/internal/store/channel"
)

// ChannelDiscoveryHandler owns channel discovery routes.
type ChannelDiscoveryHandler struct {
	channels ChannelDiscoveryStore
}

// DiscoverList handles GET /api/channels/discover.
// Returns all discoverable channels the user can browse and join.
func (h *ChannelDiscoveryHandler) DiscoverList(r api.WorkspaceScopedRequest) (api.Response, error) {
	authenticated := r.User
	workspaceID := r.WorkspaceID()

	limit, err := parseDiscoverableChannelListLimit(r.Gin.Query("limit"))
	if err != nil {
		return api.Response{}, err
	}
	options := storechannel.DiscoverableChannelListOptions{
		Limit:  limit,
		Cursor: strings.TrimSpace(r.Gin.Query("cursor")),
		Query:  strings.TrimSpace(r.Gin.Query("q")),
	}
	page := storechannel.DiscoverableChannelPage{}
	if pager, ok := h.channels.(interface {
		ListDiscoverableChannelsForUserPage(context.Context, string, string, storechannel.DiscoverableChannelListOptions) (storechannel.DiscoverableChannelPage, error)
	}); ok {
		var err error
		page, err = pager.ListDiscoverableChannelsForUserPage(r.Context(), authenticated.User.ID, workspaceID, options)
		if err != nil {
			return api.Response{}, err
		}
	} else {
		channels, err := h.channels.ListDiscoverableChannelsForUser(r.Context(), authenticated.User.ID, workspaceID)
		if err != nil {
			return api.Response{}, err
		}
		page.Channels = channels
	}

	response := make([]dto.DiscoverChannelResponse, 0, len(page.Channels))
	for _, channel := range page.Channels {
		response = append(response, discoverChannelResponseFromStore(channel))
	}
	if strings.TrimSpace(r.Gin.Query("limit")) == "" && strings.TrimSpace(r.Gin.Query("cursor")) == "" {
		return api.OK(response), nil
	}
	return api.OK(dto.DiscoverChannelPageResponse{Channels: response, HasMore: page.HasMore, NextCursor: page.NextCursor}), nil
}

// DiscoverGet handles GET /api/channels/discover/:channelId.
// Returns details for one discoverable channel by its ID.
func (h *ChannelDiscoveryHandler) DiscoverGet(r api.WorkspaceScopedRequest) (api.Response, error) {
	authenticated := r.User
	workspaceID := r.WorkspaceID()

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

	channel, err := h.channels.DiscoverableChannelForUser(r.Context(), authenticated.User.ID, workspaceID, channelID)

	if err != nil {
		return api.Response{}, err
	}
	return api.OK(discoverChannelResponseFromStore(channel)), nil
}

func parseDiscoverableChannelListLimit(rawLimit string) (int, error) {
	trimmed := strings.TrimSpace(rawLimit)
	if trimmed == "" {
		return storechannel.DefaultDiscoverableChannelListLimit, nil
	}
	limit, err := strconv.Atoi(trimmed)
	if err != nil {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit must be an integer")
	}
	if limit <= 0 {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit must be a positive integer")
	}
	if limit > storechannel.MaxDiscoverableChannelListLimit {
		return storechannel.MaxDiscoverableChannelListLimit, nil
	}
	return limit, nil
}
